/*
	File:    	CarPlayControlClient.c
	Package: 	Apple CarPlay Communication Plug-in.
	Abstract: 	n/a
	Version: 	450.14

	Disclaimer: IMPORTANT: This Apple software is supplied to you, by Apple Inc. ("Apple"), in your
	capacity as a current, and in good standing, Licensee in the MFi Licensing Program. Use of this
	Apple software is governed by and subject to the terms and conditions of your MFi License,
	including, but not limited to, the restrictions specified in the provision entitled ”Public
	Software”, and is further subject to your agreement to the following additional terms, and your
	agreement that the use, installation, modification or redistribution of this Apple software
	constitutes acceptance of these additional terms. If you do not agree with these additional terms,
	please do not use, install, modify or redistribute this Apple software.

	Subject to all of these terms and in consideration of your agreement to abide by them, Apple grants
	you, for as long as you are a current and in good-standing MFi Licensee, a personal, non-exclusive
	license, under Apple's copyrights in this original Apple software (the "Apple Software"), to use,
	reproduce, and modify the Apple Software in source form, and to use, reproduce, modify, and
	redistribute the Apple Software, with or without modifications, in binary form. While you may not
	redistribute the Apple Software in source form, should you redistribute the Apple Software in binary
	form, you must retain this notice and the following text and disclaimers in all such redistributions
	of the Apple Software. Neither the name, trademarks, service marks, or logos of Apple Inc. may be
	used to endorse or promote products derived from the Apple Software without specific prior written
	permission from Apple. Except as expressly stated in this notice, no other rights or licenses,
	express or implied, are granted by Apple herein, including but not limited to any patent rights that
	may be infringed by your derivative works or by other works in which the Apple Software may be
	incorporated.

	Unless you explicitly state otherwise, if you provide any ideas, suggestions, recommendations, bug
	fixes or enhancements to Apple in connection with this software (“Feedback”), you hereby grant to
	Apple a non-exclusive, fully paid-up, perpetual, irrevocable, worldwide license to make, use,
	reproduce, incorporate, modify, display, perform, sell, make or have made derivative works of,
	distribute (directly or indirectly) and sublicense, such Feedback in connection with Apple products
	and services. Providing this Feedback is voluntary, but if you do provide Feedback to Apple, you
	acknowledge and agree that Apple may exercise the license granted above without the payment of
	royalties or further consideration to Participant.

	The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, EXPRESS OR
	IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY
	AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR
	IN COMBINATION WITH YOUR PRODUCTS.

	IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES
	(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
	PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION
	AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
	(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
	POSSIBILITY OF SUCH DAMAGE.

	Copyright (C) 2014-2019 Apple Inc. All Rights Reserved. Not to be used or disclosed without permission from Apple.
*/

#include "CarPlayControlClient.h"
#include "CarPlayControlCommon.h"

#include "BonjourBrowser.h"
#include "HTTPUtils.h"
#include "HTTPClient.h"
#include "TickUtils.h"
#include "PairingUtils.h"
#include <stdio.h>
#include <string.h>

#include "AirPlayVersion.h"
#include "AirPlayReceiverServerPriv.h"
#include "dns_sd.h"
// #include <sys/system_properties.h>
#include <stdlib.h>


#include CF_HEADER

volatile uint8_t m_SyncNumber;
void increaseSyncNumber() {
    if (m_SyncNumber == 0xFF) {
        m_SyncNumber = 0;
    } else {
        ++m_SyncNumber;
    }
}

//===========================================================================================================================
//	Constants
//===========================================================================================================================

#define kCarPlayControlClient_ConnectionTimeoutSeconds		5

static void _CarPlayControlEnqueueTask( int eventId );
static int indexOf(char *source, int sourceOffset, int sourceCount,
        char* target, int targetOffset, int targetCount,
        int fromIndex);
//===========================================================================================================================
//	Configuration
//===========================================================================================================================

ulog_define( CarPlayControlClient, kLogLevelAll, kLogFlags_Default, "CarPlayControl", NULL );
#define cpcc_ulog( LEVEL, ... )		ulog( &log_category_from_name( CarPlayControlClient ), ( LEVEL ), __VA_ARGS__ )

ulog_define( CarPlayControlServerHTTP, kLogLevelNotice, kLogFlags_Default, "CarPlayControlServerHTTP",  NULL );
#define cpcc_http_ucat()					&log_category_from_name( CarPlayControlServerHTTP )
#define cpcc_http_ulog( LEVEL, ... )		ulog( aprs_http_ucat(), (LEVEL), __VA_ARGS__ )
//===========================================================================================================================
// Prototypes
//===========================================================================================================================

static void _CarPlayControlClientRemoveController( CarPlayControlClientRef inClient, CarPlayControllerRef inController );
static OSStatus _CreateHTTPClientRef(char * hostNameWithInterfaceNdx,uint16_t port,dispatch_queue_t httpQueue);

//===========================================================================================================================
// AirPlayClientConnection
//===========================================================================================================================
struct AirPlayClientConnection
{
	MFiSAPRef					MFiSAP;
	uint8_t						ourSK[ 32 ];
	uint8_t						ourPK[ 32 ];
	uint8_t						aesKey[ 16 ];
	uint8_t						aesIV[ 16 ];
	PairingSessionRef			pairSetupSessionHomeKit;
	PairingSessionRef			pairVerifySessionHomeKit;
	AirPlayReceiverSessionRef	session;			// Session this connection is associated with.
	sockaddr_ip 				peerAddr;
	char 				        peerUrl[ 100 ];
};

static struct AirPlayClientConnection * mAirPlayClientConnection = NULL;


//===========================================================================================================================
//	CarPlayControlClientConnect
//===========================================================================================================================

typedef struct
{
	CarPlayControllerRef	controller;
	OSStatus				err;
	void *					inCtx;
} _ConnectContext;



//===========================================================================================================================
//	CarPlayBonjourService
//===========================================================================================================================

typedef struct CarPlayBonjourService			CarPlayBonjourService;
typedef const struct CarPlayBonjourService		*CarPlayBonjourServiceRef;

struct CarPlayBonjourService
{
	CFRuntimeBase				base;				// Must be first
	dispatch_queue_t			queue;				// Serialization queue
	CFDictionaryRef				bonjourservice;		// Bonjour service
	CFStringRef					serviceType;		// Bonjour service type
	char *						hostName;			// Service host name
	uint16_t					port;				// Service port number
	uint32_t					interfaceNdx;		// Service interface index
	OSStatus					resolutionError;	// Address resolution error
};


//===========================================================================================================================
//	SharkCarPlay
//===========================================================================================================================
static void _CarPlayControlClientEvent( int eventId );
static void _CarPlayControlClientAudioFocusGain( int targetChannel, int eventId );
static void _CarPlayControlClientAudioFocusLost( int targetChannel, int eventId );
static CarPlayControlClientRef	gCarPlayClient = NULL;
static CarPlayBonjourServiceRef	gCarPlayService = NULL;

static uint8_t *  				gCacheBodyPtr =NULL; //全局缓存
static size_t    				gCacheBodyOffset=0;
static HTTPClientRef		    gHttpClient = NULL; //CarPlay会话session HttpClient
static uint64_t                 gRemoteDeviceID = 0;
static CFStringRef              gRemotePublicHKID = NULL;
static uint64_t                 gMeSessionUUID = 0;
static uint8_t                  gMeSessionUUIDArray[ 16 ];
static int64_t                  gPeerEventPort = 0;
static int64_t                  gPeerTimingPort = 0;
static int64_t                  gPeerScreenType = 0;
static int64_t                  gPeerScreenPort = 0;
static int64_t                  gPeerAudioType = 0;
static int64_t                  gPeerAudioPort = 0;
static int64_t                  gClientStarted = 0;
static int64_t                  gScreenStarted = 0;
static volatile int64_t         gHomeKitEnable = 1; //是否使用homekit加解密
static volatile int64_t         gBonjourPairingHK = 1; //Bonjour告知信息是否使用homekit加解密
static uint16_t                 gUsbVid = 0x0000;
static uint16_t                 gUsbPid = 0x0000;
static float                 	gPeerSourceVersion = 0.0;
static uint64_t                 gPeerAirplayFeatures = 0;
static char	                    gOEMBrand [ 200 ] = "ApplePie";

//iap2 mdnsd相关
static char	                    gBonjourIPAddress [ 100 ] = "";
static char	                    gBonjourDeviceID  [ 100 ] = "";
static char	                    gBonjourPublicKey [ 100 ] = "";
static int	                    gBonjourPort  = 0;

//===========================================================================================================================
// DNServiceContext
//===========================================================================================================================

typedef struct DNSServiceContext			DNSServiceContext;
typedef void ( *DNSServiceHandleError )( DNSServiceContext* inServiceCxt, OSStatus inErr, void *inCtx );
#define DNSServiceContextForget( X )		ForgetCustom( X, _DNSServiceDispose )

static CarPlayControlClientDelegate    gCarPlayControlClientDelegate;

struct DNSServiceContext
{
	DNSServiceHandleError		errorHandler;
	void *						errorHandlerCtx;
	DNSServiceRef				service;
	dispatch_queue_t			queue;
	dispatch_source_t			source;
};

static void	_DNSServiceSocketEventCallback( void *inCtx )
{
	DNSServiceContext *		ctx = (DNSServiceContext*) inCtx;
	OSStatus				err;

	err = DNSServiceProcessResult( ctx->service );
	if( err && ctx->errorHandler )
	{
		ctx->errorHandler( ctx, err, ctx->errorHandlerCtx );
	}
}

static void	_DNSServiceCleanup( void *inCtx )
{
	DNSServiceContext *		ctx = (DNSServiceContext*) inCtx;

	DNSServiceRefDeallocate( ctx->service );
	dispatch_release_null_safe( ctx->queue );
	free( ctx );
}

static OSStatus
	DNSServiceContextCreate(
		DNSServiceContext **outServiceCtx, DNSServiceRef inService,
		DNSServiceHandleError inErrorHandler, void *inErrorHandlerCtx )
{
	OSStatus				err;
	DNSServiceContext *		ctx;
	int						dnsSocket;

	ctx = calloc( 1, sizeof( *ctx ) );
	require_action( ctx, exit, err = kNoMemoryErr );

	dnsSocket = DNSServiceRefSockFD( inService );
	require_action( IsValidSocket( dnsSocket ), exit, err = kUnknownErr );

	ctx->queue = dispatch_queue_create( "CarPlayControl DNSServiceContext", NULL );
	require_action( ctx->queue, exit, err = kNoMemoryErr );

	ctx->source = dispatch_source_create( DISPATCH_SOURCE_TYPE_READ, dnsSocket, 0, ctx->queue );
	require_action( ctx->source, exit, err = kNoMemoryErr );

	// Success ( No more errors after this point, so assume ownership of "inService" )

	err = kNoErr;

	ctx->errorHandler = inErrorHandler;
	ctx->errorHandlerCtx = inErrorHandlerCtx;
	ctx->service = inService;
	dispatch_set_context( ctx->source, ctx );
	dispatch_source_set_event_handler_f( ctx->source, _DNSServiceSocketEventCallback );
	dispatch_source_set_cancel_handler_f( ctx->source, _DNSServiceCleanup );
	dispatch_resume( ctx->source );

	*outServiceCtx = ctx;
	ctx = NULL;

exit:
	free( ctx );
	return( err );
}

static void _DNSServiceDispose( DNSServiceContext *inServiceCtx )
{
	dispatch_source_t source = inServiceCtx->source;
	dispatch_source_cancel( source );
	arc_safe_dispatch_release( source );
}

//===========================================================================================================================
//	_CarPlayBonjourServiceFinalize
//===========================================================================================================================

static void _CarPlayBonjourServiceFinalize( CFTypeRef inObj )
{
	CarPlayBonjourService *		service	= (CarPlayBonjourService*) inObj;

	dispatch_forget( &service->queue );
	ForgetCF( &service->bonjourservice );
	ForgetCF( &service->serviceType );
	ForgetMem( &service->hostName );
	cpcc_ulog( kLogLevelVerbose, "Finalized CarPlayBonjourService [%p]\n", inObj );
}

//===========================================================================================================================
//	CarPlayBonjourServiceGetTypeID
//===========================================================================================================================

static void _CarPlayBonjourServiceGetTypeID( void *inCtx )
{
	static const CFRuntimeClass		kCarPlayBonjourServiceClass =
	{
		0,											// version
		"CarPlayBonjourService",					// className
		NULL,										// init
		NULL,										// copy
		_CarPlayBonjourServiceFinalize,				// finalize
		NULL,										// equal -- NULL means pointer equality.
		NULL,										// hash  -- NULL means pointer hash.
		NULL,										// copyFormattingDesc
		NULL,										// copyDebugDesc
		NULL,										// reclaim
		NULL										// refcount
	};

	*( (CFTypeID*) inCtx ) = _CFRuntimeRegisterClass( &kCarPlayBonjourServiceClass );
}

static CFTypeID CarPlayBonjourServiceGetTypeID( void )
{
	static dispatch_once_t		serviceInitOnce = 0;
	static CFTypeID				serviceTypeID = _kCFRuntimeNotATypeID;

	dispatch_once_f( &serviceInitOnce, &serviceTypeID, _CarPlayBonjourServiceGetTypeID );
	return( serviceTypeID );
}

//===========================================================================================================================
//	_CarPlayBonjourServiceResolveReply
//===========================================================================================================================

typedef struct
{
	dispatch_semaphore_t	semaphore;
	Boolean					resolved;
	OSStatus				err;
	char *					hostname;
	uint16_t				port;
	uint32_t				interfaceNdx;
} _ResolveContext;

static void DNSSD_API
	_CarPlayBonjourServiceResolveReply(
		DNSServiceRef inServiceRef, DNSServiceFlags inFlags, uint32_t inIfNdx, DNSServiceErrorType inErr, const char* inFullName,
		const char* inTargetName, uint16_t inPort, uint16_t inTXTLen, const unsigned char* inTXTPtr, void* inCtx )
{
	_ResolveContext *		ctx = (_ResolveContext*) inCtx;

	(void) inServiceRef;
	(void) inFlags;
	(void) inIfNdx;
	(void) inFullName;
	(void) inTXTLen;
	(void) inTXTPtr;

	require_quiet( !ctx->resolved, exit );
	require_action( !inErr, exit, ctx->err = inErr );

	ctx->err = inErr;
	if( !ctx->err )
	{
		ctx->resolved = true;
		ctx->hostname = strdup( inTargetName );
		ctx->port = ntoh16( inPort );
		ctx->interfaceNdx = inIfNdx;
	}

exit:
	if( !( inFlags & kDNSServiceFlagsMoreComing ) )
		dispatch_semaphore_signal( ctx->semaphore );
}

//===========================================================================================================================
//	_CarPlayBonjourServiceResolveAddress
//===========================================================================================================================

static void _CarPlayBonjourServiceResolveAddress( void *inCtx )
{
	OSStatus					err;
	CarPlayBonjourService *		service = (CarPlayBonjourService*) inCtx;
	DNSServiceRef				dnsService = NULL;
	DNSServiceContext *			dnsServiceCtx = NULL;
	_ResolveContext				resolveCtx;
	dispatch_semaphore_t		dnsServiceSemaphore;
	long						timeout;
	char *						serviceType = NULL;
	uint32_t					ifNdx;
	char *						name = NULL;
	char *						domain = NULL;

	// Set up the context

	memset( &resolveCtx, 0, sizeof ( resolveCtx ) );

	dnsServiceSemaphore = dispatch_semaphore_create( 0 );
	require_action( dnsServiceSemaphore, exit, err = kNoMemoryErr );
	resolveCtx.semaphore = dnsServiceSemaphore;

	// Initiate the resolve

	serviceType = CFCopyCString( service->serviceType, NULL );
	ifNdx = (uint32_t) CFDictionaryGetInt64( service->bonjourservice, CFSTR( kBonjourDeviceKey_InterfaceIndex ), NULL );
	name = CFDictionaryCopyCString( service->bonjourservice, CFSTR( kBonjourDeviceKey_RawName ), NULL );
	domain = CFDictionaryCopyCString( service->bonjourservice, CFSTR( kBonjourDeviceKey_Domain ), NULL );
	require_action( name && serviceType && domain, exit, err = kNoMemoryErr );

	err = DNSServiceResolve( &dnsService, 0, ifNdx, name, serviceType, domain, _CarPlayBonjourServiceResolveReply, &resolveCtx );
	require_noerr( err, exit );

	err = DNSServiceContextCreate( &dnsServiceCtx, dnsService, NULL, NULL );
	require_noerr_action( err, exit, DNSServiceRefDeallocate( dnsService ) );

	// Wait for a result (or timeout)

	timeout = dispatch_semaphore_wait( dnsServiceSemaphore, dispatch_time( DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC ) );
	require_action( timeout == 0, exit, err = kTimeoutErr );

	// Handle the result

	err = resolveCtx.err;
	require_noerr( err, exit );

	ForgetMem( &service->hostName );
	service->hostName = resolveCtx.hostname;
	service->port = resolveCtx.port;
	service->interfaceNdx = resolveCtx.interfaceNdx;

exit:
	service->resolutionError = err;

	cpcc_ulog( kLogLevelNotice, "CarPlayBonjourService [%p] resolved to: %s port: %u interfaceNdx: %lu (%#m)\n",
		service, service->hostName ? service->hostName : "<null>", service->port, service->interfaceNdx, err );

	dispatch_release_null_safe( dnsServiceSemaphore );
	DNSServiceContextForget( &dnsServiceCtx );
	ForgetMem( &serviceType );
	ForgetMem( &name );
	ForgetMem( &domain );

	CFRelease( service );
}

static OSStatus CarPlayBonjourServiceResolveAddress( CarPlayBonjourServiceRef inService )
{
	CFRetain( inService );
	dispatch_async_f( inService->queue, (void*) inService, _CarPlayBonjourServiceResolveAddress );

	return( kNoErr );
}

//===========================================================================================================================
//	CarPlayBonjourServiceIsSameBonjourService
//===========================================================================================================================

static Boolean CarPlayBonjourServiceIsSameBonjourService( CarPlayBonjourServiceRef inService, CFDictionaryRef inBonjourService )
{
	return CFEqual( inService->bonjourservice, inBonjourService );
}

//===========================================================================================================================
//	CarPlayBonjourServiceIsSameBonjourService
//===========================================================================================================================

static Boolean CarPlayBonjourServiceIsWiFi( CarPlayBonjourServiceRef inService )
{
	return CFDictionaryGetBoolean( inService->bonjourservice, CFSTR( kBonjourDeviceKey_WiFi ), NULL );
}

//===========================================================================================================================
//	CarPlayBonjourServiceGetAddress
//===========================================================================================================================

typedef struct
{
	CarPlayBonjourServiceRef	service;
	const char *				hostName;
	uint16_t					port;
	uint32_t					interfaceNdx;
	OSStatus					err;
} _GetAddressContext;

static void _CarPlayBonjourServiceGetAddress( void *inCtx )
{
	OSStatus					err;
	_GetAddressContext *		context	= (_GetAddressContext*) inCtx;

	require_action( context->service->hostName, exit, err = kNotFoundErr );

	context->hostName = context->service->hostName;
	context->port = context->service->port;
	context->interfaceNdx = context->service->interfaceNdx;

	err = kNoErr;

exit:
	context->err = err;
}

static OSStatus
	CarPlayBonjourServiceGetAddress(
		CarPlayBonjourServiceRef inService, const char **outHostname, uint16_t *outPort, uint32_t *outInterfaceNdx )
{
	_GetAddressContext		context	= { inService, NULL, 0, 0, kNoErr };

	dispatch_sync_f( inService->queue, &context, _CarPlayBonjourServiceGetAddress );
	require_noerr( context.err, exit );

	*outHostname = context.hostName;
	*outPort = context.port;
	*outInterfaceNdx = context.interfaceNdx;

exit:
	return context.err;
}

//===========================================================================================================================
//	CarPlayBonjourServiceCreate
//===========================================================================================================================

static OSStatus
	CarPlayBonjourServiceCreate(
		CarPlayBonjourServiceRef *outController, CFDictionaryRef inService, CFStringRef inServiceType )
{
	OSStatus					err;
	CarPlayBonjourService *		obj;
	size_t						extraLen;

	extraLen = sizeof( *obj ) - sizeof( obj->base );
	obj = (CarPlayBonjourService*) _CFRuntimeCreateInstance( NULL, CarPlayBonjourServiceGetTypeID(), (CFIndex) extraLen, NULL );
	require_action( obj, exit, err = kNoMemoryErr );
	memset( ( (uint8_t *) obj ) + sizeof( obj->base ), 0, extraLen );

	obj->queue = dispatch_queue_create( "CarPlayBonjourService", NULL );
	require_action( obj->queue, exit, err = kNoMemoryErr );

	obj->bonjourservice = (CFDictionaryRef) CFRetain( inService );
	obj->serviceType = (CFStringRef) CFRetain( inServiceType );

	err = kNoErr;

	cpcc_ulog( kLogLevelTrace, "Created CarPlayBonjourService [%p] for: %1@\n", obj, inServiceType, inService );

	*outController = obj;
	obj = NULL;

exit:
	CFReleaseNullSafe( obj );
	return( err );
}

//===========================================================================================================================
//	CarPlayController
//===========================================================================================================================

typedef struct CarPlayController
{
	CFRuntimeBase				base;					// Must be first
	CarPlayControlClientRef		client;					// Weak reference to creator (Not retained)
	dispatch_queue_t			internalQueue;			// Internal synchronization queue
	CFDictionaryRef				device;					// Bonjour device
	CFMutableDictionaryRef		activeServices;			// Active Bonjour services
	CFMutableDictionaryRef		inactiveWiFiServices;	// Inactive WiFi Bonjour services
} CarPlayController;

static CFDictionaryRef _CarPlayControllerCopyCurrentDevice( CarPlayControllerRef inController );

//===========================================================================================================================
//	_CarPlayControllerFinalize
//===========================================================================================================================

static void	_CarPlayControllerFinalize( CFTypeRef inObj )
{
	CarPlayController *		controller = (CarPlayController*) inObj;

	dispatch_forget( &controller->internalQueue );
	ForgetCF( &controller->device );
	ForgetCF( &controller->activeServices );
	ForgetCF( &controller->inactiveWiFiServices );
	controller->client = NULL;

	cpcc_ulog( kLogLevelVerbose, "Finalized CarPlayController [%p]\n", inObj );
}

//===========================================================================================================================
//	CarPlayControllerGetTypeID
//===========================================================================================================================

static void _CarPlayControllerGetTypeID( void *inCtx )
{
	static const CFRuntimeClass		kCarPlayControllerClass =
	{
		0,								// version
		"CarPlayController",			// className
		NULL,							// init
		NULL,							// copy
		_CarPlayControllerFinalize,		// finalize
		NULL,							// equal -- NULL means pointer equality.
		NULL,							// hash  -- NULL means pointer hash.
		NULL,							// copyFormattingDesc
		NULL,							// copyDebugDesc
		NULL,							// reclaim
		NULL							// refcount
	};

	*( (CFTypeID*) inCtx ) = _CFRuntimeRegisterClass( &kCarPlayControllerClass );
}

CFTypeID CarPlayControllerGetTypeID( void )
{
	static dispatch_once_t		carPlayControllerInitOnce = 0;
	static CFTypeID				carPlayControllerTypeID = _kCFRuntimeNotATypeID;

	dispatch_once_f( &carPlayControllerInitOnce, &carPlayControllerTypeID, _CarPlayControllerGetTypeID );
	return( carPlayControllerTypeID );
}

//===========================================================================================================================
//	CarPlayControllerCreate
//===========================================================================================================================

static OSStatus _CarPlayControllerCreate( CarPlayController **outController, CarPlayControlClientRef inClient )
{
	OSStatus				err;
	CarPlayController *		obj;
	size_t					extraLen;

	extraLen = sizeof( *obj ) - sizeof( obj->base );
	obj = (CarPlayController*) _CFRuntimeCreateInstance( NULL, CarPlayControllerGetTypeID(), (CFIndex) extraLen, NULL );
	require_action( obj, exit, err = kNoMemoryErr );
	memset( ( (uint8_t *) obj ) + sizeof( obj->base ), 0, extraLen );

	require_action( inClient, exit, err = kParamErr );
	obj->client = inClient;

	obj->internalQueue = dispatch_queue_create( "CarPlayController", NULL );
	require_action( obj->internalQueue, exit, err = kNoMemoryErr );

	obj->activeServices = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
	require_action( obj->activeServices, exit, err = kNoMemoryErr );

	obj->inactiveWiFiServices = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
	require_action( obj->inactiveWiFiServices, exit, err = kNoMemoryErr );

	err = kNoErr;

	cpcc_ulog( kLogLevelTrace, "Created controller [%p]\n", obj );

	*outController = obj;
	obj = NULL;

exit:
	CFReleaseNullSafe( obj );
	return( err );
}

//===========================================================================================================================
//	_CarPlayControllerDeactivateService
//===========================================================================================================================

static void _CarPlayControllerDeactivateService( const void *inService, void *inCtx )
{
	CarPlayControllerRef			controller = (CarPlayControllerRef) inCtx;
	CFDictionaryRef					bonjourService = (CFDictionaryRef) inService;
	CFTypeRef						serviceInterfaceNdx;
	CarPlayBonjourServiceRef		service;
	Boolean							wifi;

	serviceInterfaceNdx = CFDictionaryGetValue( bonjourService, CFSTR( kBonjourDeviceKey_InterfaceIndex ) );
	service = CFDictionaryGetValue( controller->activeServices, serviceInterfaceNdx );
	check( service && CarPlayBonjourServiceIsSameBonjourService( service, bonjourService ) );

	wifi = CFDictionaryGetBoolean( bonjourService, CFSTR( kBonjourDeviceKey_WiFi ), NULL );

	// Remove the service from the active list and (if it is a WiFi service) add it to the inactive service list

	CFRetain( service );

	CFDictionaryRemoveValue( controller->activeServices, serviceInterfaceNdx );

	if( wifi )
		CFDictionarySetValue( controller->inactiveWiFiServices, serviceInterfaceNdx, service );

	cpcc_ulog( kLogLevelNotice, "Controller [%p] %s Service [%p]\n",
		 controller, wifi ? "Deactivated" : "Removed", service );

	CFRelease( service );
}

//===========================================================================================================================
//	_CarPlayControllerActivateService
//===========================================================================================================================

static void _CarPlayControllerActivateService( const void *inService, void *inCtx )
{
	OSStatus						err;
	CarPlayControllerRef			controller = (CarPlayControllerRef) inCtx;
	CFDictionaryRef					bonjourService = (CFDictionaryRef) inService;
	CFTypeRef						serviceInterfaceNdx;
	CarPlayBonjourServiceRef		service;

	serviceInterfaceNdx = CFDictionaryGetValue( bonjourService, CFSTR( kBonjourDeviceKey_InterfaceIndex ) );
	require_quiet( !CFDictionaryContainsKey( controller->activeServices, serviceInterfaceNdx ), exit );

	// If we have an inactive service on the same interface, move it to the active list (we'll validate it below)

	service = CFDictionaryGetValue( controller->inactiveWiFiServices, serviceInterfaceNdx );
	if( service )
	{
		CFRetain( service );
		CFDictionaryRemoveValue( controller->inactiveWiFiServices, serviceInterfaceNdx );
		CFDictionarySetValue( controller->activeServices, serviceInterfaceNdx, service );
		CFRelease( service );
	}

	// Verify if we have a existing and valid active service

	service = CFDictionaryGetValue( controller->activeServices, serviceInterfaceNdx );
	if( !service || !CarPlayBonjourServiceIsSameBonjourService( service, bonjourService ) )
	{
		err = CarPlayBonjourServiceCreate( &service, bonjourService,
					CFDictionaryGetCFString( controller->device, CFSTR( kBonjourDeviceKey_ServiceType ), NULL ) );
		if( err == kNoErr )
		{
			CFDictionarySetValue( controller->activeServices, serviceInterfaceNdx, service );
			CFRelease( service );
		}
		else
		{
			service = NULL;
		}
	}

	// Resolve the service (if we are resurrecting from the inactive list we still do this in case the address / port number changed)
	// 解析服务（如果我们从非活动列表中复活，我们仍然会这样做，以防地址/端口号发生变化）

	if( service )
	{
		CarPlayBonjourServiceResolveAddress( service );
	}

	cpcc_ulog( kLogLevelNotice, "Controller [%p] Activated Service [%p]\n", controller, service );

exit:
	return;
}

//===========================================================================================================================
//	_CarPlayControllerUpdateDevice
//===========================================================================================================================

typedef struct
{
	CarPlayController *		controller;
	CFDictionaryRef			device;
	CFIndex					newServiceCount;
}
_UpdateDeviceContext;

static void _CarPlayControllerUpdateInternal( void *inCtx )
{
	_UpdateDeviceContext *		ctx = (_UpdateDeviceContext*) inCtx;
	CFDictionaryRef				oldDevice;
	CFArrayRef					removedServices;
	CFArrayRef					deviceServices;

	check( ctx->device );
	removedServices = CFDictionaryGetCFArray( ctx->device, CFSTR( kBonjourDeviceKey_RemovedServices ), NULL );
	deviceServices = CFDictionaryGetCFArray( ctx->device, CFSTR( kBonjourDeviceKey_Services ), NULL );

	oldDevice = ctx->controller->device;
	CFRetainNullSafe( oldDevice );

	if( ctx->device )	BonjourDevice_MergeInfo( &ctx->controller->device, ctx->device );
	else				BonjourDevice_RemoveInterfaceInfo( &ctx->controller->device, "", true );

	// Deactivate removed services first

	if( removedServices )
	{
		CFArrayApplyFunction( removedServices, CFRangeMake( 0, CFArrayGetCount( removedServices ) ),
			_CarPlayControllerDeactivateService, (void*) ctx->controller );
	}

	// Activate new / existing services

	if( deviceServices )
	{
		CFArrayApplyFunction( deviceServices, CFRangeMake( 0, CFArrayGetCount( deviceServices ) ),
			_CarPlayControllerActivateService, (void*) ctx->controller );
	}

	// Count the services

	ctx->newServiceCount = CFDictionaryGetCount( ctx->controller->activeServices ) +
							CFDictionaryGetCount( ctx->controller->inactiveWiFiServices );

	// Clean up

	CFReleaseNullSafe( oldDevice );
}

static void	_CarPlayControllerUpdate( CarPlayController *inController, CFDictionaryRef inDevice, CFIndex *outServiceCount )
{
	_UpdateDeviceContext		ctx = { inController, inDevice, 0 };

	require( inController, exit );

	dispatch_sync_f( inController->internalQueue, &ctx, _CarPlayControllerUpdateInternal );

	if( outServiceCount )
		*outServiceCount = ctx.newServiceCount;

exit:
	return;
}

//===========================================================================================================================
//	_CarPlayControllerCopyBestService
//===========================================================================================================================

typedef struct
{
	CarPlayControllerRef		controller;
	CarPlayBonjourServiceRef	bestService;
	Boolean						bestServiceIsActive;
	OSStatus					err;
} _CopyBestServiceContext;

static void _CarPlayControllerCopyBestService( void *inCtx )
{
	_CopyBestServiceContext *		ctx = (_CopyBestServiceContext*) inCtx;
	CFArrayRef						serviceKeys;
	CFIndex							serviceNdx, serviceCount;
	CarPlayBonjourServiceRef		carPlayService;
	Boolean							active = false;

	serviceKeys = CFDictionaryCopyKeys( ctx->controller->activeServices, NULL );
	require_action( serviceKeys, exit, ctx->err = kNoMemoryErr );

	// Pick the best active service (wired beats wireless)

	for( serviceNdx = 0, serviceCount = CFArrayGetCount( serviceKeys ); serviceNdx < serviceCount; ++serviceNdx )
	{
		carPlayService = CFDictionaryGetValue( ctx->controller->activeServices,
								CFArrayGetValueAtIndex( serviceKeys, serviceNdx ) );
		if( !CarPlayBonjourServiceIsWiFi( carPlayService ) )
		{
			ReplaceCF( &ctx->bestService, carPlayService );
			active = true;
			break;
		}
		else if( !ctx->bestService )
		{
			ctx->bestService = CFRetain( carPlayService );
			active = true;
		}
	}
	ForgetCF( &serviceKeys );

	// If there were no active services, then choose any inactive wireless service

	if( !ctx->bestService )
	{
		serviceKeys = CFDictionaryCopyKeys( ctx->controller->inactiveWiFiServices, NULL );
		require_action( serviceKeys, exit, ctx->err = kNoMemoryErr );

		if( CFArrayGetCount( serviceKeys ) > 0 )
		{
			carPlayService = CFDictionaryGetValue( ctx->controller->inactiveWiFiServices,
									CFArrayGetValueAtIndex( serviceKeys, serviceNdx ) );
			ctx->bestService = CFRetain( carPlayService );
		}
		ForgetCF( &serviceKeys );
	}

//	cpcc_ulog( kLogLevelTrace, "Controller [%p] found best Service [%p] (%s) from:\nActiveServices:%@\nInactiveServices:%@\n",
//		ctx->controller, ctx->bestService, ctx->bestService ? ( active ? "Active" : "Inactive" ) : "N/A",
//		ctx->controller->activeServices, ctx->controller->inactiveWiFiServices );
	require_action_quiet( ctx->bestService, exit, ctx->err = kNotFoundErr );

	ctx->bestServiceIsActive = active;

exit:
	return;
}

static OSStatus
	CarPlayControllerCopyBestService(
		CarPlayControllerRef inController, CarPlayBonjourServiceRef *outBestService, Boolean *outBestServiceIsActive )
{
	_CopyBestServiceContext		ctx = { inController, NULL, false, kNoErr };

	dispatch_sync_f( inController->internalQueue, &ctx, _CarPlayControllerCopyBestService );
	require_noerr( ctx.err, exit );

	*outBestService = ctx.bestService;
	*outBestServiceIsActive = ctx.bestServiceIsActive;

exit:
	return ctx.err;
}

//===========================================================================================================================
//	_CarPlayControllerCopyCurrentDevice
//===========================================================================================================================

typedef struct
{
	CarPlayControllerRef	controller;
	CFDictionaryRef *		device;
} _CopyCurrentDeviceContext;

static void _CarPlayControllerCopyCurrentDeviceInternal( void *inCtx )
{
	_CopyCurrentDeviceContext		*ctx = (_CopyCurrentDeviceContext*) inCtx;
	*ctx->device = (CFDictionaryRef) CFRetain( ctx->controller->device );
}

static CFDictionaryRef _CarPlayControllerCopyCurrentDevice( CarPlayControllerRef inController )
{
	_CopyCurrentDeviceContext		ctx;
	CFDictionaryRef					device;

	ctx.controller = inController;
	ctx.device = &device;

	dispatch_sync_f( inController->internalQueue, &ctx, _CarPlayControllerCopyCurrentDeviceInternal );

	return( device );
}

//===========================================================================================================================
//	CarPlayControllerCopyName
//===========================================================================================================================

OSStatus CarPlayControllerCopyName( CarPlayControllerRef inController, CFStringRef *outName )
{
	OSStatus			err;
	CFDictionaryRef		device = NULL;
	CFStringRef			name;

	require_action( inController, exit, err = kParamErr );
	require_action( outName, exit, err = kParamErr );

	device = _CarPlayControllerCopyCurrentDevice( inController );
	name = CFDictionaryGetCFString( device, CFSTR( kBonjourDeviceKey_Name ), NULL );
	require_action( name, exit, err = kUnknownErr );

	*outName = (CFStringRef) CFRetain( name );
	err = kNoErr;

exit:
	CFRelease( device );
	return( err );
}

//===========================================================================================================================
//	CarPlayControllerGetBluetoothMacAddress
//===========================================================================================================================

OSStatus CarPlayControllerGetBluetoothMacAddress( CarPlayControllerRef inController, uint8_t outAddress[ 6 ] )
{
	OSStatus			err;
	CFDictionaryRef		device = NULL;

	require_action( inController, exit, err = kParamErr );

	device = _CarPlayControllerCopyCurrentDevice( inController );
	BonjourDevice_GetDeviceID( device, outAddress, &err );
	require_noerr( err, exit );

exit:
	CFRelease( device );
	return( err );
}

//===========================================================================================================================
//	CarPlayControllerCopySourceVersion
//===========================================================================================================================

OSStatus	CarPlayControllerCopySourceVersion( CarPlayControllerRef inController, CFStringRef *outSourceVersion )
{
	OSStatus			err;
	CFDictionaryRef		device = NULL;
	CFStringRef			sourceVersion = NULL;

	require_action( inController, exit, err = kParamErr );
	require_action( outSourceVersion, exit, err = kParamErr );

	device = _CarPlayControllerCopyCurrentDevice( inController );
	sourceVersion = BonjourDevice_CopyCFString( device, kAPSCarPlayControlTxtRecordKey_SourceVersion, &err );
	require_noerr( err, exit );

	*outSourceVersion = sourceVersion;
	sourceVersion = NULL;

exit:
	CFRelease( device );
	CFReleaseNullSafe( sourceVersion );

	return( err );
}

//===========================================================================================================================
//	CarPlayControllerGetInterfaceName
//===========================================================================================================================

OSStatus CarPlayControllerGetInterfaceName( CarPlayControllerRef inController, CFStringRef *outName )
{
    OSStatus			err;
    CFDictionaryRef		device = NULL;
    CFStringRef			name = NULL;
    CFIndex				i, n;
    CFDictionaryRef		serviceDict;

    require_action( inController, exit, err = kParamErr );
    require_action( outName, exit, err = kParamErr );

    device = _CarPlayControllerCopyCurrentDevice( inController );
    CFArrayRef services = NULL;
    services = CFDictionaryGetCFArray( device, CFSTR(kBonjourDeviceKey_Services), NULL);

    require_action_quiet( services, exit, err = kUnknownErr );

    n = CFArrayGetCount( services );
    for( i = 0; i < n; ++i )
    {
        serviceDict = CFArrayGetCFDictionaryAtIndex( services, i, NULL );
        if( !serviceDict ) continue;

        name = CFDictionaryGetCFString( serviceDict, CFSTR( kBonjourDeviceKey_InterfaceName ), NULL );

        if (name != NULL) {
            break;
        }
    }

    require_action( name, exit, err = kUnknownErr );

    *outName = (CFStringRef) CFRetain( name );
    err = kNoErr;

exit:
    CFRelease( device );
    return( err );
}

//===========================================================================================================================
//	CarPlayControllerGetServicesCount
//===========================================================================================================================

OSStatus CarPlayControllerGetServicesCount( CarPlayControllerRef inController, CFIndex * outCount )
{
	OSStatus			err;
	CFDictionaryRef		device = NULL;
	CFIndex				n;

	require_action( inController, exit, err = kParamErr );

	device = _CarPlayControllerCopyCurrentDevice( inController );
	CFArrayRef services = NULL;
	services = CFDictionaryGetCFArray( device, CFSTR(kBonjourDeviceKey_Services), NULL );

	require_action_quiet( services, exit, err = kUnknownErr );

	n = CFArrayGetCount( services );

	*outCount = n;
	err = kNoErr;

exit:
	CFRelease( device );
	return( err );
}

//===========================================================================================================================
//	_CarPlayControllerForgetInactiveServices
//===========================================================================================================================

typedef struct
{
	CarPlayControllerRef	controller;
	CFIndex					serviceCount;
} _ForgetInactiveServicesContext;

static void _CarPlayControllerForgetInactiveServicesInternal( void *inCtx )
{
	_ForgetInactiveServicesContext *		context =	(_ForgetInactiveServicesContext*) inCtx;

	CFDictionaryRemoveAllValues( context->controller->inactiveWiFiServices );
	context->serviceCount = CFDictionaryGetCount( context->controller->activeServices ) +
								CFDictionaryGetCount( context->controller->inactiveWiFiServices );
}

static void _CarPlayControllerForgetInactiveServices( CarPlayControllerRef inController, CFIndex *outServiceCount )
{
	_ForgetInactiveServicesContext		context	= { inController, 0 };

	dispatch_sync_f( inController->internalQueue, &context, _CarPlayControllerForgetInactiveServicesInternal );

	if( outServiceCount )
		*outServiceCount = context.serviceCount;
}

//===========================================================================================================================
//	CarPlayControlClient
//===========================================================================================================================

typedef struct CarPlayControlClient
{
	CFRuntimeBase					base;				// CF type info. Must be first.
	dispatch_queue_t				internalQueue;
	dispatch_queue_t				internalRequestQueue;
	dispatch_queue_t				httpQueue;

	dispatch_queue_t				eventQueue;
	dispatch_queue_t				httpClientQueue;
	CarPlayControlClientCallback	eventCallback;
	void *							eventCtx;

	Boolean							started;
	BonjourBrowserRef				browser;
	CFMutableArrayRef				controllers;

	AirPlayReceiverServerRef		server;
	uint64_t						deviceID;
} CarPlayControlClient;

//===========================================================================================================================
//	Prototypes
//===========================================================================================================================

static void _CarPlayControlClientEnsureStarted( void *inCtx );
static void _CarPlayControlClientEnsureStopped( void *inCtx );
static void _CarPlayControlClientPostEvent( CarPlayControlClientRef inClient, CarPlayControlClientEvent inEvent, const void *inEventInfo );
static void _CarPlayControlClientBrowseCallback( BonjourBrowserEventType inEventType, CFDictionaryRef inEventInfo, void *inCtx );

//===========================================================================================================================
//	_CarPlayControlClientFinalize
//===========================================================================================================================

static void	_CarPlayControlClientFinalize( CFTypeRef inCF )
{
	//最后一步，释放资源
	CarPlayControlClient *		client = (CarPlayControlClient*) inCF;

	cpcc_ulog( kLogLevelTrace, "CarPlayControlClient %p Finalized\n", inCF );

	dispatch_forget( &client->internalQueue );
	dispatch_forget( &client->internalRequestQueue );
	dispatch_forget( &client->httpQueue );
	dispatch_forget( &client->eventQueue );
	dispatch_forget( &client->httpClientQueue );
	check( !client->browser );
	ForgetCF( &client->controllers );
	ForgetCF( &client->server );

	gClientStarted = 0;
	gScreenStarted = 0;
	if(mAirPlayClientConnection != NULL)
	{
		if(mAirPlayClientConnection->pairSetupSessionHomeKit != NULL){
			PairingSessionReset(mAirPlayClientConnection->pairSetupSessionHomeKit);
			ForgetCF( &mAirPlayClientConnection->pairSetupSessionHomeKit );
			mAirPlayClientConnection->pairSetupSessionHomeKit = NULL;
			cpcc_ulog( kLogLevelTrace, "CarPlayControlClient pairSetupSessionHomeKit Finalized Successfully.\n" );
		}
		if(mAirPlayClientConnection->pairVerifySessionHomeKit != NULL){
			PairingSessionReset(mAirPlayClientConnection->pairVerifySessionHomeKit);
			ForgetCF( &mAirPlayClientConnection->pairVerifySessionHomeKit );
			mAirPlayClientConnection->pairVerifySessionHomeKit = NULL;
			cpcc_ulog( kLogLevelTrace, "CarPlayControlClient pairVerifySessionHomeKit Finalized Successfully.\n" );
		}
		CFReleaseNullSafe( mAirPlayClientConnection );
	}
	if(gHttpClient != NULL){
		HTTPClientForget( &gHttpClient );
	}
	cpcc_ulog( kLogLevelTrace, "CarPlayControlClient %p Finalized Successfully.\n", inCF );
}

//===========================================================================================================================
//	_CarPlayControlClientGetTypeID
//===========================================================================================================================

static void _CarPlayControlClientGetTypeID( void *inCtx )
{
	static const CFRuntimeClass		kCarPlayControlClientClass =
	{
		0,								// version
		"CarPlayControlClient",			// className
		NULL,							// init
		NULL,							// copy
		_CarPlayControlClientFinalize,	// finalize
		NULL,							// equal -- NULL means pointer equality.
		NULL,							// hash  -- NULL means pointer hash.
		NULL,							// copyFormattingDesc
		NULL,							// copyDebugDesc
		NULL,							// reclaim
		NULL							// refcount
	};

	*( (CFTypeID*) inCtx ) = _CFRuntimeRegisterClass( &kCarPlayControlClientClass );
}

CFTypeID CarPlayControlClientGetTypeID( void )
{
	static dispatch_once_t		carPlayControlClientInitOnce = 0;
	static CFTypeID				carPlayControlClientTypeID = _kCFRuntimeNotATypeID;

	dispatch_once_f( &carPlayControlClientInitOnce, &carPlayControlClientTypeID, _CarPlayControlClientGetTypeID );
	return( carPlayControlClientTypeID );
}

//===========================================================================================================================
//	CarPlayControlClientCreateWithServer
//===========================================================================================================================

OSStatus CarPlayControlClientCreateWithServer(
			CarPlayControlClientRef * outClient, AirPlayReceiverServerRef inServer,
			CarPlayControlClientCallback inCallback, void * inCtx )
{
	OSStatus					err;
	CarPlayControlClient *		obj = NULL;
	size_t						extraLen;

	require_action( outClient, exit, err = kParamErr );

	extraLen = sizeof( *obj ) - sizeof( obj->base );
	obj = (CarPlayControlClient*) _CFRuntimeCreateInstance( NULL, CarPlayControlClientGetTypeID(), (CFIndex) extraLen, NULL );
	require_action( obj, exit, err = kNoMemoryErr );
	memset( ( (uint8_t *) obj ) + sizeof( obj->base ), 0, extraLen );

	obj->internalQueue = dispatch_queue_create( "CarPlayControlClient Internal", 0 );
	require_action( obj->internalQueue, exit, err = kNoMemoryErr );

	obj->internalRequestQueue = dispatch_queue_create( "CarPlayControlClient InternalRequest", 0 );
	require_action( obj->internalRequestQueue, exit, err = kNoMemoryErr );

	obj->httpQueue = dispatch_queue_create( "CarPlayControlClient http", 0 );
	require_action( obj->httpQueue, exit, err = kNoMemoryErr );

	require_action( inCallback, exit, err = kParamErr );
	obj->eventCallback = inCallback;
	obj->eventCtx = inCtx;
	obj->eventQueue = dispatch_queue_create( "CarPlayControlClient Event", 0 );
	require_action( obj->eventQueue, exit, err = kNoMemoryErr );

	obj->httpClientQueue = dispatch_queue_create( "CarPlayControlClient HttpClientEvent", 0 );
	require_action( obj->httpClientQueue, exit, err = kNoMemoryErr );

	obj->server = inServer;
	CFRetainNullSafe( obj->server );

	obj->controllers = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
	require_action( obj->controllers, exit, err = kNoMemoryErr );

	*outClient = obj;
	obj = NULL;

	err = kNoErr;

exit:
	CFReleaseNullSafe( obj );
	return( err );
}

//===========================================================================================================================
//	CarPlayControlClientStart
//===========================================================================================================================

OSStatus CarPlayControlClientStart( CarPlayControlClientRef inClient )
{
	OSStatus		err;
	cpcc_ulog( kLogLevelNotice, "CarPlayControlClientStart: comming \n" );
	require_action( inClient, exit, err = kParamErr );

	CFRetain( inClient );
	dispatch_async_f( inClient->internalQueue, (void*) inClient, _CarPlayControlClientEnsureStarted );
	err = kNoErr;

	cpcc_ulog( kLogLevelNotice, "CarPlayControlClientStart: %#m\n", err );

exit:
    cpcc_ulog( kLogLevelTrace, "CarPlayControlClientEnsureStarted exit: %#m\n", err );
	return( err );
}

//===========================================================================================================================
//	_CarPlayControlClientEnsureStarted
//===========================================================================================================================

static void _CarPlayControlClientEnsureStarted( void *inCtx )
{
	OSStatus					err;
	CarPlayControlClient *		client = (CarPlayControlClient*) inCtx;

	require_action_quiet( !client->started, exit, err = kNoErr );

	if( client->deviceID == 0 && client->server != NULL)
		client->deviceID = AirPlayGetDeviceID(client->server, NULL );

	check( !client->browser );
	err = BonjourBrowser_Create( &client->browser, "CarPlayControlClient" );
	require_noerr( err, exit );

	BonjourBrowser_SetDispatchQueue( client->browser, client->internalQueue );
	BonjourBrowser_SetEventHandler( client->browser, _CarPlayControlClientBrowseCallback, client );
	err = BonjourBrowser_Start( client->browser,
			kAPSCarPlayControlBonjourServiceType,
			kAPSCarPlayControlBonjourServiceDomain,
			NULL,
			kBonjourBrowserFlag_StandardID );
	require_noerr( err, exit );


	CFRetain( client ); // Released on stop event
	client->started = true;

exit:

	if( err )
	{
	    cpcc_ulog( kLogLevelTrace, "_CarPlayControlClientEnsureStarted: %#m\n", err );
		BonjourBrowser_Forget( &client->browser );
		_CarPlayControlClientPostEvent( client, kCarPlayControlClientEvent_Stopped, &err );
	}
	CFRelease( client );
}

//===========================================================================================================================
//	CarPlayControlClientStop
//===========================================================================================================================

OSStatus CarPlayControlClientStop( CarPlayControlClientRef inClient )
{
	OSStatus		err;

	require_action( inClient, exit, err = kParamErr );

	CFRetain( inClient );
	dispatch_async_f( inClient->internalQueue, (void*) inClient, _CarPlayControlClientEnsureStopped );
	err = kNoErr;

exit:
	return( err );
}

//===========================================================================================================================
//	_CarPlayControlClientEnsureStopped
//===========================================================================================================================

static void	_CarPlayControlClientEnsureStopped( void *inCtx )
{
	CarPlayControlClient *		client = (CarPlayControlClient*) inCtx;

	require_quiet( client->started, exit );
	BonjourBrowser_Stop( client->browser );
	cpcc_ulog( kLogLevelTrace, "BonjourBrowser_Stop. \n");
	exit(0);

exit:
	CFRelease( client );
}

//===========================================================================================================================
//	_CarPlayControlClientPostEvent
//===========================================================================================================================

typedef struct
{
	CarPlayControlClientRef		client;
	CarPlayControlClientEvent	event;
	CarPlayControllerRef		controller;
	OSStatus					err;
	const void *				eventInfo;
} CallbackContext;

static void _CarPlayControlClientCallEventCallback( void *inCtx )
{
	CallbackContext *		ctx = (CallbackContext*) inCtx;

	cpcc_ulog( kLogLevelTrace, "Posting event: %s\n", CarPlayControlEventToString( ctx->event ) );

	ctx->client->eventCallback( ctx->client, ctx->event, (void*) ctx->eventInfo, ctx->client->eventCtx );
	CFReleaseNullSafe( ctx->controller );
	CFReleaseNullSafe( ctx->client );
	free( ctx );
}

static void _CarPlayControlClientPostEvent( CarPlayControlClientRef inClient, CarPlayControlClientEvent inEvent, const void *inEventInfo )
{
	CallbackContext *		callbackCtx;

	callbackCtx = calloc( 1, sizeof( CallbackContext ) );
	require( callbackCtx, exit );
	callbackCtx->client = (CarPlayControlClientRef) CFRetain( inClient );
	callbackCtx->event = inEvent;

	switch( inEvent )
	{
		case kCarPlayControlClientEvent_AddOrUpdateController:
		case kCarPlayControlClientEvent_RemoveController:
            cpcc_ulog( kLogLevelTrace, "_CarPlayControlClientPostEvent add or update or remove. \n");
			callbackCtx->controller = (CarPlayControllerRef) CFRetain( (CarPlayControllerRef) inEventInfo );
			callbackCtx->eventInfo = callbackCtx->controller;
			break;
		case kCarPlayControlClientEvent_Stopped:
            cpcc_ulog( kLogLevelTrace, "_CarPlayControlClientPostEvent: kCarPlayControlClientEvent_Stopped. \n" );
			callbackCtx->err = inEventInfo ? *( (OSStatus*) inEventInfo ) : kNoErr;
			callbackCtx->eventInfo = &callbackCtx->err;
			break;
		default:
			check( "Unhandled CarPlayControlClientEvent" == 0 );
			break;
	}

	dispatch_async_f( inClient->eventQueue, callbackCtx, _CarPlayControlClientCallEventCallback );

exit:
	return;
}

//===========================================================================================================================
//	_CarPlayControlClientHandleBonjourAddOrUpdate
//===========================================================================================================================

static void _CarPlayControlClientHandleBonjourAddOrUpdate( CarPlayControlClientRef inClient, CFDictionaryRef inEventInfo )
{
	uint64_t				deviceID;
	CFIndex					ndx, count;
	CarPlayController *		controller;
	CFStringRef			    publicHKID = NULL;
	CFStringRef			    protocolVersion = NULL;
	CFStringRef			    sourceVersion = NULL;
	CFStringRef			    features = NULL;

	// See if we have an existing entry to update

	controller = NULL;
	deviceID = BonjourDevice_GetDeviceID( inEventInfo, NULL, NULL );
	publicHKID = BonjourDevice_CopyCFString( inEventInfo, kAirPlayTXTKey_PublicHKID, NULL );
	protocolVersion = BonjourDevice_CopyCFString( inEventInfo, kAirPlayTXTKey_ProtocolVersion, NULL );
	sourceVersion = BonjourDevice_CopyCFString( inEventInfo, kAirPlayTXTKey_SourceVersion, NULL );
	features = BonjourDevice_CopyCFString( inEventInfo, kAirPlayTXTKey_Features, NULL );

	char* featuresStr = NULL;
	char* sourceVersionStr = NULL;
	featuresStr = CFStringGetCStringPtr( features, kCFStringEncodingUTF8 );
	sourceVersionStr = CFStringGetCStringPtr( sourceVersion, kCFStringEncodingUTF8 );
	//kAirPlayFeature_HKPairingAndEncrypt
	cpcc_ulog( kLogLevelTrace, "_CarPlayControlClientHandleBonjourAddOrUpdate \n" );
//	cpcc_ulog( kLogLevelTrace, "_CarPlayControlClientHandleBonjourAddOrUpdate inEventInfo = %@ \n" ,inEventInfo);
//	cpcc_ulog( kLogLevelTrace, "_CarPlayControlClientHandleBonjourAddOrUpdate features = %s \n",featuresStr );
//	cpcc_ulog( kLogLevelTrace, "_CarPlayControlClientHandleBonjourAddOrUpdate sourceVersion =  %s \n",sourceVersionStr );

	//patch for wireless ignore mac's book start >>>
	char dnsName [ 100 ];
	BonjourDevice_GetDNSName( inEventInfo, 0, dnsName, 100);
	cpcc_ulog( kLogLevelTrace, "_CarPlayControlClientHandleBonjourAddOrUpdate dnsName = %s .\n" ,dnsName );

	if(strstr(dnsName,"mac") != NULL || strstr(dnsName,"Mac") != NULL )
	{
		cpcc_ulog( kLogLevelTrace, "_CarPlayControlClientHandleBonjourAddOrUpdate dnsName = %s is MacBook ignore.\n" ,dnsName );
		return;
	}
	//patch for wireless ignore mac's book end <<<

	if ( featuresStr != NULL && strlen( featuresStr ) > 0)
	{
		char	featureHigh [ 20 ];
		char	featureLow [ 20 ];
		int index=indexOf(featuresStr, 0, 20, ",", 0, 1, 0);
		if(index > 0 )
		{
			strlcpy(featureHigh,featuresStr + (index+1),(strlen( featuresStr ) - index));
			strlcpy(featureLow,featuresStr,(index+1));
//			cpcc_ulog( kLogLevelTrace, "featureHigh %s\n", featureHigh );
//			cpcc_ulog( kLogLevelTrace, "featureLow %s\n", featureLow );
			//0x44440B80
			//123456789a
			uint32_t feature = CFStringGetIntValue( features );

			int32_t high = TextToInt32( featureHigh, 20, 10 );
			int32_t low = TextToInt32( featureLow, 20, 10 );

			uint8_t highBuf [4];
			uint8_t lowBuf [4];
			WriteBig32(highBuf, high);
			WriteBig32(lowBuf, low);

			uint8_t featuresBuf [ 8 ];
			memcpy(featuresBuf,highBuf,4);
			memcpy(featuresBuf+4,lowBuf,4);

			cpcc_ulog( kLogLevelTrace, "featureHead featuresBuf = %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x  \n" ,
					featuresBuf[0],featuresBuf[1],featuresBuf[2],featuresBuf[3],featuresBuf[4],
					featuresBuf[5],featuresBuf[6],featuresBuf[7]);

			uint8_t  pairingHK = (featuresBuf[3] & 0x40) >> 6; //kAirPlayFeature_HKPairingAndEncrypt
			cpcc_ulog( kLogLevelTrace, "featureHead pairingHK = %d  \n" ,pairingHK);
			gBonjourPairingHK = pairingHK;

			AirPlayFeatures	airPlayFeatures = ReadBig64( featuresBuf );
			gPeerAirplayFeatures = airPlayFeatures;
//			cpcc_ulog( kLogLevelTrace, "featureHead high = %d  \n" ,high);
//			cpcc_ulog( kLogLevelTrace, "featureHead low = %d  \n" ,low);
//			cpcc_ulog( kLogLevelTrace, "featureHead airPlayFeatures = %llu  \n" ,airPlayFeatures);

		}
	}
	gRemoteDeviceID = deviceID;
	gRemotePublicHKID = publicHKID;
	for( ndx = 0, count = CFArrayGetCount( inClient->controllers ); ndx < count; ++ndx )
	{
		controller = (CarPlayController*) CFArrayGetValueAtIndex( inClient->controllers, ndx );
		if( BonjourDevice_GetDeviceID( controller->device, NULL, NULL ) == deviceID )
		{
			CFRetain( controller );
			break;
		}
		else
		{
			controller = NULL;
		}
	}

	// Otherwise create new

	if( !controller )
	{
		_CarPlayControllerCreate( &controller, inClient );
		if( controller )
			CFArrayAppendValue( inClient->controllers, controller );
	}

	// Update the controller and notify our client

	if( controller )
	{
		_CarPlayControllerUpdate( controller, inEventInfo, NULL );
		_CarPlayControlClientPostEvent( inClient, kCarPlayControlClientEvent_AddOrUpdateController, controller );
		CFRelease( controller );
	}
}

//===========================================================================================================================
//	_CarPlayControlClientRemoveController
//===========================================================================================================================

static void _CarPlayControlClientRemoveController( CarPlayControlClientRef inClient, CarPlayControllerRef inController )
{
	CFIndex			ndx;

	// Find the controller and remove it if there are no more services

	CFRetain( inController );

	ndx = CFArrayGetFirstIndexOfValue( inClient->controllers, CFRangeMake( 0, CFArrayGetCount( inClient->controllers ) ), inController );
	check( ndx != kCFNotFound );

	if( ndx != kCFNotFound )
	{
		// Remove and notify our client
		CFArrayRemoveValueAtIndex( inClient->controllers, ndx );
		_CarPlayControlClientPostEvent( inClient, kCarPlayControlClientEvent_RemoveController, inController );
	}

	CFRelease( inController );
}

//===========================================================================================================================
//	_CarPlayControlClientHandleBonjourRemove
//===========================================================================================================================

static void _CarPlayControlClientHandleBonjourRemove( CarPlayControlClientRef inClient, CFDictionaryRef inEventInfo )
{
	uint64_t				deviceID;
	CFIndex					ndx, count, serviceCount;
	CarPlayController *		controller;

	// Find the controller and updated it
	controller = NULL;
	deviceID = BonjourDevice_GetDeviceID( inEventInfo, NULL, NULL );
	for( ndx = 0, count = CFArrayGetCount( inClient->controllers ); ndx < count; ++ndx )
	{
		controller = (CarPlayController*) CFArrayGetValueAtIndex( inClient->controllers, ndx );
		if( BonjourDevice_GetDeviceID( controller->device, NULL, NULL ) == deviceID )
		{
			_CarPlayControllerUpdate( controller, inEventInfo, &serviceCount );

			cpcc_ulog( kLogLevelTrace, "CarPlayControlClientHandleBonjourRemove serviceCount: %d\n", serviceCount );

			// Remove the device if there are no more services
			if( serviceCount == 0 )
				_CarPlayControlClientRemoveController( inClient, controller );
			else
				_CarPlayControlClientPostEvent( inClient, kCarPlayControlClientEvent_RemoveController, controller );

			break;
		}
	}
}

//===========================================================================================================================
//	_CarPlayControlClientHandleBonjourStopOrRestart
//===========================================================================================================================

static void _CarPlayControlClientHandleBonjourStopOrRestart( CarPlayControlClient * inClient, BonjourBrowserEventType inEventType )
{
	CFIndex					ndx, count;
	CarPlayController *		controller;

	for( ndx = 0, count = CFArrayGetCount( inClient->controllers ); ndx < count; ++ndx )
	{
		controller = (CarPlayController*) CFArrayGetValueAtIndex( inClient->controllers, ndx );
		_CarPlayControllerUpdate( controller, NULL, NULL );

		// Notify client of removal if restarting
		if( inEventType == kBonjourBrowserEventType_Restarted )
			_CarPlayControlClientPostEvent( inClient, kCarPlayControlClientEvent_RemoveController, controller );
	}
	CFArrayRemoveAllValues( inClient->controllers );

	// Notify client of stop
	if( inEventType == kBonjourBrowserEventType_Stop )
	{
		_CarPlayControlClientPostEvent( inClient, kCarPlayControlClientEvent_Stopped, NULL );
		inClient->started = false;
		BonjourBrowser_Forget( &inClient->browser );
		CFRelease( inClient ); // Balance retain in _CarPlayControlClientEnsureStarted
	}
}

//===========================================================================================================================
//	_CarPlayControlClientBrowseCallback
//===========================================================================================================================

static void _CarPlayControlClientBrowseCallback( BonjourBrowserEventType inEventType, CFDictionaryRef inEventInfo, void *inCtx )
{
	CarPlayControlClient *		client = (CarPlayControlClient*) inCtx;

//	cpcc_ulog( kLogLevelTrace, "BrowseCallback: event=%s, info=%@\n", BonjourBrowserEventTypeToString(inEventType), inEventInfo );
	cpcc_ulog( kLogLevelTrace, "BrowseCallback: event=%s .\n", BonjourBrowserEventTypeToString(inEventType) );

	if( inEventType == kBonjourBrowserEventType_AddOrUpdateDevice )
	{
		_CarPlayControlClientHandleBonjourAddOrUpdate( client, inEventInfo );
	}
	else if( inEventType == kBonjourBrowserEventType_RemoveDevice )
	{
		_CarPlayControlClientHandleBonjourRemove( client, inEventInfo );
	}
	else if( inEventType == kBonjourBrowserEventType_Restarted || inEventType == kBonjourBrowserEventType_Stop )
	{
		_CarPlayControlClientHandleBonjourStopOrRestart( client, inEventType );
	}
}

/**
 * Code shared by String and StringBuffer to do searches. The
 * source is the character array being searched, and the target
 * is the string being searched for.
 *
 * @param   source       the characters being searched.
 * @param   sourceOffset offset of the source string.
 * @param   sourceCount  count of the source string.
 * @param   target       the characters being searched for.
 * @param   targetOffset offset of the target string.
 * @param   targetCount  count of the target string.
 * @param   fromIndex    the index to begin searching from.
 */
static int indexOf(char *source, int sourceOffset, int sourceCount,
        char* target, int targetOffset, int targetCount,
        int fromIndex) {
    if (fromIndex >= sourceCount) {
        return (targetCount == 0 ? sourceCount : -1);
    }
    if (fromIndex < 0) {
        fromIndex = 0;
    }
    if (targetCount == 0) {
        return fromIndex;
    }

    char first = target[targetOffset];
    int max = sourceOffset + (sourceCount - targetCount);

    for (int i = sourceOffset + fromIndex; i <= max; i++) {
        /* Look for first character. */
        if (source[i] != first) {
            while (++i <= max && source[i] != first);
        }

        /* Found first character, now look at the rest of v2 */
        if (i <= max) {
            int j = i + 1;
            int end = j + targetCount - 1;
            for (int k = targetOffset + 1; j < end && source[j]
                    == target[k]; j++, k++);

            if (j == end) {
                /* Found whole string. */
                return i - sourceOffset;
            }
        }
    }
    return -1;
}

//===========================================================================================================================
//	_CarPlayControlClientRtspOptions
//===========================================================================================================================

static OSStatus
	_CarPlayControlClientRtspOptions(
		CarPlayControlClientRef inClient, CarPlayBonjourServiceRef inService, const char *inCommand )
{
	OSStatus			err;
	char *				rtspHostName = NULL;
	HTTPMessageRef		httpMessage = NULL;


	// Build the request

	err = HTTPMessageCreate( &httpMessage );
	require_noerr( err, exit );

	char	url[ 100 ];
	char	ipv6[ 100 ];
	memset(url,0,100);
	memcpy(url, mAirPlayClientConnection->peerUrl,100);
	int index=indexOf(url, 0, 100, "%", 0, 1, 0);
	//%usb0
	if(index>0)
	{
		strlcpy(ipv6,url,(index+1));
//		cpcc_ulog( kLogLevelTrace, "TinkerIPV6 %s\n", ipv6 );
	}else{
		//无线的IPV4
		strlcpy(ipv6,url,strlen(url));
	}
	asprintf( &rtspHostName, "%s%s", "rtsp://", ipv6 );
//	cpcc_ulog( kLogLevelTrace, "rtspHostName %s\n", rtspHostName );
	err = HTTPHeader_InitRequest( &httpMessage->header, kHTTPMethodString_OPTIONS, rtspHostName, kRTSPVersionString_1pt1 );
	require_noerr( err, exit );

	//log for header
//	cpcc_ulog( kLogLevelTrace, "TinkerHeader %s\n", httpMessage->header.buf );
	//CSeq
	char CSeq[32];
	snprintf( CSeq, sizeof(CSeq), "%d", m_SyncNumber );
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_CSeq, CSeq );
	require_noerr( err, exit );

	//User-Agent
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_UserAgent, kAirPlayUserAgentStr );
	require_noerr( err, exit );

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Request **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	// send the request

	err = HTTPClientSendMessageSync( gHttpClient, httpMessage );
	require_noerr( err, exit );
	increaseSyncNumber();
	// Read the response header

	require_action( httpMessage->header.statusCode != 0, exit, err = kResponseErr );
	require_action( IsHTTPStatusCode_Success( httpMessage->header.statusCode ), exit, err = HTTPStatusToOSStatus( httpMessage->header.statusCode ) );

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Response **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	const char *			publicOptions		    = NULL;
	size_t					publicOptionsLen		= 0;

	err = (int) HTTPGetHeaderField( httpMessage->header.buf, httpMessage->header.len, kHTTPHeader_Public, NULL, NULL, &publicOptions, &publicOptionsLen, NULL );
	require_noerr_quiet( err, exit );
	cpcc_ulog( kLogLevelWarning, "CarPlayControl rtsp options %s \n", publicOptions);


	dispatch_async_f(inClient->httpClientQueue, SHARK_EVENT_RTSP_OPTIONS, _CarPlayControlClientEvent);

exit:
	if( err )	cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" failed    @ %N: %#m\n", inCommand, err );
	else		cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" completed @ %N\n", inCommand);

	CFReleaseNullSafe( httpMessage );

	return( err );
}

//===========================================================================================================================
//	_CarPlayControlClientRtspSetup
//===========================================================================================================================

static OSStatus
	_CarPlayControlClientRtspSetup(
		CarPlayControlClientRef inClient, CarPlayBonjourServiceRef inService, const char *inCommand )
{
	OSStatus			err;
	char *				rtspHostName = NULL;
	HTTPMessageRef		httpMessage = NULL;

	// Build the request

	err = HTTPMessageCreate( &httpMessage );
	require_noerr( err, exit );

	//the url is consist of target host ip address and clientSessionID
	//uint64_t clientSessionID; // Unique session ID from the client.
//	char url[53]="rtsp://fe80::ec4e:8eff:fe62:1d30/12818258285706628577";
	char	url[ 100 ];
	char	ipv6[ 100 ];
	memset(url,0,100);
	memcpy(url, mAirPlayClientConnection->peerUrl,100);
	int index=indexOf(url, 0, 100, "%", 0, 1, 0);
	//%usb0
	if(index>0)
	{
		strlcpy(ipv6,url,(index+1));
//		cpcc_ulog( kLogLevelTrace, "TinkerIPV6 %s\n", ipv6 );
	}else{
		strlcpy(ipv6,url,strlen(url));
	}

	sockaddr_ip		sip;
	size_t			sipLen;
	StringToSockAddr( url, &sip, sizeof( sip ), &sipLen );
	// Setup the session
	uint8_t sessionUUID[ 16 ];
	memset(sessionUUID,0,16);
	int timingPortLocal;

	cpcc_ulog( kLogLevelTrace, "_requestCreateSharkCarPlaySession remoteDeviceId %d \n", gRemoteDeviceID );
	err = _requestCreateSharkCarPlaySession(sip,gRemoteDeviceID,inClient->server, &(mAirPlayClientConnection->session), true ,sessionUUID);
	cpcc_ulog( kLogLevelTrace, "_requestCreateSharkCarPlaySession %d \n", err );
	require_noerr( err, exit );

	AirPlayReceiverSessionPeerAddressSetup(mAirPlayClientConnection->session, &mAirPlayClientConnection->peerAddr);

	if( gHomeKitEnable == 1 )
	{
		err = AirPlayReceiverSharkCarPlayBeforeSessionSetup( (mAirPlayClientConnection->session), mAirPlayClientConnection->pairVerifySessionHomeKit,&timingPortLocal,gHttpClient);
	}else {
		err = AirPlayReceiverSharkCarPlayBeforeSessionSetup( (mAirPlayClientConnection->session), NULL,&timingPortLocal,gHttpClient);
	}
	require_noerr( err, exit );
	cpcc_ulog( kLogLevelTrace, "_requestCreateSharkCarPlaySession timingPortLocal = %d \n", timingPortLocal );

	uint64_t meSessionID = ReadBig64(sessionUUID);
	cpcc_ulog( kLogLevelTrace, "_requestCreateSharkCarPlaySession sessionUUID = %llu \n", meSessionID );
	gMeSessionUUID = meSessionID;
	memset(gMeSessionUUIDArray,0,sizeof(gMeSessionUUIDArray));
	memcpy(gMeSessionUUIDArray,sessionUUID,sizeof(gMeSessionUUIDArray));

	asprintf( &rtspHostName, "%s%s%s%llu", "rtsp://", ipv6, "/",gMeSessionUUID);
	cpcc_ulog( kLogLevelTrace, "rtspHostName %s\n", rtspHostName );
	err = HTTPHeader_InitRequest( &httpMessage->header, kHTTPMethodString_SETUP, rtspHostName, kRTSPVersionString_1pt1 );
	require_noerr( err, exit );

	//log for header
	cpcc_ulog( kLogLevelTrace, "TinkerHeader %s\n", httpMessage->header.buf );
	//CSeq
	char CSeq[32];
	snprintf( CSeq, sizeof(CSeq), "%d", m_SyncNumber );
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_CSeq, CSeq );
	require_noerr( err, exit );

	//User-Agent
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_UserAgent, kAirPlayUserAgentStr );
	require_noerr( err, exit );

	//Content-Type
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_ContentType, kMIMEType_AppleBinaryPlist );
	require_noerr( err, exit );

	//Payload data

	CFDictionaryRef			requestDict =NULL;
	CFDictionaryRef			featuresDict =NULL;
	CFMutableArrayRef		featuresArray =NULL;
	if( !requestDict )
	{
		requestDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
	}
//	if( !featuresDict )
//	{
//		featuresDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
//	}
	if( !featuresArray )
	{
		featuresArray = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
	}

	char	macAddress[ 100 ];
	// __system_property_get("sys.shark.interface.mac-address", macAddress);

	char	deviceId[ 40 ];
	// __system_property_get("sys.xq.product.deviceid", deviceId);

	CFDictionarySetCString( requestDict, CFSTR( kAirPlayKey_Model ), "iPhone9,4" ,kSizeCString);
	CFDictionarySetCString( requestDict, CFSTR( kAirPlayKey_DeviceID ), deviceId ,kSizeCString);
	//CFDictionarySetCString( requestDict, CFSTR( kAirPlayKey_Port_Timing ),  ,kSizeCString);
	CFDictionarySetInt64( requestDict, CFSTR( kAirPlayKey_Port_Timing ), timingPortLocal );
	CFDictionarySetCString( requestDict, CFSTR( kAirPlayKey_MACAddress ), macAddress ,kSizeCString);
	CFDictionarySetCString( requestDict, CFSTR( kAirPlayKey_OSBuildVersion ), "19H380" ,kSizeCString); //IOS 16
	CFDictionarySetCString( requestDict, CFSTR( kAirPlayKey_SourceVersion ), "387.2" ,kSizeCString);
	char	oemBrand [ 200 ] =  "ApplePie";
	// __system_property_get("persist.sys.oem.brand", oemBrand);
	CFDictionarySetCString( requestDict, CFSTR( kAirPlayKey_Name ), oemBrand ,kSizeCString);

//	CFDictionarySetData( requestDict, CFSTR( kAirPlayKey_SessionUUID ), sessionUUID, sizeof( sessionUUID ) );
	char				identifierBuf[ 64 ];
	UUIDtoCString( sessionUUID, false, identifierBuf );
	cpcc_ulog( kLogLevelTrace, "The tinker sessionId = %s \n" ,identifierBuf);

	CFDictionarySetCString( requestDict, CFSTR( kAirPlayKey_SessionUUID ), identifierBuf, kSizeCString );

	//features
	if ( featuresDict )
	{
		CFDictionarySetBoolean( featuresDict, CFSTR( kAirPlayKeyControllerFeature_ViewAreas ), kCFBooleanTrue );
		CFDictionarySetBoolean( featuresDict, CFSTR( kAirPlayKeyControllerFeature_EnhancedSiri ), kCFBooleanTrue );
		CFDictionarySetBoolean( featuresDict, CFSTR( kAirPlayKeyControllerFeature_AltScreen ), kCFBooleanTrue );
		CFDictionarySetBoolean( featuresDict, CFSTR( kAirPlayKeyControllerFeature_UIContext ), kCFBooleanTrue );
		CFDictionarySetBoolean( featuresDict, CFSTR( kAirPlayKeyControllerFeature_CornerMasks ), kCFBooleanTrue );
		CFDictionarySetBoolean( featuresDict, CFSTR( kAirPlayKeyControllerFeature_FocusTransfer ), kCFBooleanTrue );
		CFDictionarySetValue( requestDict, CFSTR( kAirPlayKey_ControllerFeatures ), featuresDict);
	}

	if( featuresArray )
	{
		CFArrayAppendValue( featuresArray, CFSTR(kAirPlayKeyControllerFeature_UIContext) );
		CFArrayAppendValue( featuresArray, CFSTR(kAirPlayKeyControllerFeature_ViewAreas) );
		CFArrayAppendValue( featuresArray, CFSTR(kAirPlayKeyControllerFeature_CornerMasks) );
		CFArrayAppendValue( featuresArray, CFSTR(kAirPlayKeyControllerFeature_FocusTransfer) );
		CFDictionarySetValue( requestDict, CFSTR( kAirPlayKey_ControllerFeatures ), featuresArray);
	}

	if( gHomeKitEnable == 0)
	{
		CFDictionarySetInt64( requestDict, CFSTR( kAirPlayKey_EncryptionType ), kAirPlayEncryptionType_MFi_SAPv1);

		uint8_t	inKeyBuf[ 16 ] = { 0 };
		MFiSAP_Encrypt(mAirPlayClientConnection->MFiSAP, mAirPlayClientConnection->aesKey, 16, inKeyBuf);

		CFDictionarySetData( requestDict, CFSTR( kAirPlayKey_EncryptionKey ), inKeyBuf, 16 );
		CFDictionarySetData( requestDict, CFSTR( kAirPlayKey_EncryptionIV ), mAirPlayClientConnection->aesIV, 16 );

		AirPlayReceiverSessionSetSecurityInfo( mAirPlayClientConnection->session, mAirPlayClientConnection->aesKey, mAirPlayClientConnection->aesIV );

	}



	//[Dictionary] Controller supported features.
	const uint8_t*      ptr;
	size_t              len;
    if (requestDict) {
        ptr = CFBinaryPlistV0Create(requestDict, &len, NULL);
        err = HTTPMessageSetBodyPtr(httpMessage, kMIMEType_AppleBinaryPlist, ptr, len);
    }

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Request **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	// send the request

	err = HTTPClientSendMessageSync( gHttpClient, httpMessage );
	require_noerr( err, exit );
	increaseSyncNumber();
	// Read the response header

	require_action( httpMessage->header.statusCode != 0, exit, err = kResponseErr );
	require_action( IsHTTPStatusCode_Success( httpMessage->header.statusCode ), exit, err = HTTPStatusToOSStatus( httpMessage->header.statusCode ) );

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Response **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	CFDictionaryRef responseDict = (CFDictionaryRef)CFBinaryPlistV0CreateWithData(httpMessage->bodyPtr, httpMessage->bodyOffset, &err);
	require_noerr( err, exit );

	cpcc_ulog( kLogLevelTrace, "Accessory SETUP responseDict = %@ \n", responseDict );

	int64_t eventPort=CFDictionaryGetInt64(responseDict,  CFSTR(kAirPlayKey_Port_Event), &err);
	require_noerr( err, exit );
	gPeerEventPort = eventPort;
	cpcc_ulog( kLogLevelTrace, "peer eventPort %d \n", eventPort );

	AirPlayReceiverSessionControlSetEventUrl(mAirPlayClientConnection->session, mAirPlayClientConnection->peerUrl, eventPort);

	int64_t timingPortRemote = CFDictionaryGetInt64(responseDict, CFSTR(kAirPlayKey_Port_Timing), &err);//车机侧session timingport
    require_noerr( err, exit );
    gPeerTimingPort = timingPortRemote;
    cpcc_ulog( kLogLevelTrace, "peer timingPortRemote %d \n", timingPortRemote );
	CFDictionaryRef  responseParams = NULL;
	CFDictionarySetCString( responseDict, CFSTR( kAirPlayKey_OSBuildVersion ), "19H380" ,kSizeCString); //IOS 16
	err = AirPlayReceiverSessionSetup( (mAirPlayClientConnection->session), responseDict,&responseParams);
	require_noerr( err, exit );

	AirPlayReceiverSharkCarPlayEventConnection((mAirPlayClientConnection->session));

	//同时需要启动时间timing
	AirPlayReceiverControlIdleStateTransitionActive((mAirPlayClientConnection->session));

	dispatch_async_f(inClient->httpClientQueue, SHARK_EVENT_SESSION_SETUP, _CarPlayControlClientEvent);

exit:
	if( err )	cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" failed    @ %N: %#m\n", inCommand, err );
	else		cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" completed @ %N\n", inCommand);

	if( requestDict ) CFReleaseNullSafe(requestDict);
	if( featuresDict ) CFReleaseNullSafe(featuresDict);
	if( responseDict ) CFReleaseNullSafe(responseDict);
	CFReleaseNullSafe( httpMessage );

	return( err );
}


//===========================================================================================================================
//	_CarPlayControlClientRtspSetupScreen
//===========================================================================================================================

static OSStatus
	_CarPlayControlClientRtspSetupScreen(
		CarPlayControlClientRef inClient, CarPlayBonjourServiceRef inService, const char *inCommand )
{
	OSStatus			err;
	char *				rtspHostName = NULL;
	HTTPMessageRef		httpMessage = NULL;

	// Build the request

	err = HTTPMessageCreate( &httpMessage );
	require_noerr( err, exit );

	char	url[ 100 ];
	char	ipv6[ 100 ];
	memset(url,0,100);
	memcpy(url, mAirPlayClientConnection->peerUrl,100);
	int index=indexOf(url, 0, 100, "%", 0, 1, 0);
	//%usb0
	if(index>0)
	{
		strlcpy(ipv6,url,(index+1));
//		cpcc_ulog( kLogLevelTrace, "TinkerIPV6 %s\n", ipv6 );
	}else{
		strlcpy(ipv6,url,strlen(url));
	}

	asprintf( &rtspHostName, "%s%s%s%llu", "rtsp://", ipv6, "/",gMeSessionUUID);
//	cpcc_ulog( kLogLevelTrace, "rtspHostName %s\n", rtspHostName );
	err = HTTPHeader_InitRequest( &httpMessage->header, kHTTPMethodString_SETUP, rtspHostName, kRTSPVersionString_1pt1 );
	require_noerr( err, exit );

	//log for header
//	cpcc_ulog( kLogLevelTrace, "TinkerHeader %s\n", httpMessage->header.buf );
	//CSeq
	char CSeq[32];
	snprintf( CSeq, sizeof(CSeq), "%d", m_SyncNumber );
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_CSeq, CSeq );
	require_noerr( err, exit );

	//User-Agent
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_UserAgent, kAirPlayUserAgentStr );
	require_noerr( err, exit );

	//Content-Type
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_ContentType, kMIMEType_AppleBinaryPlist );
	require_noerr( err, exit );

	//Payload data

	CFDictionaryRef			requestDict =NULL;
	if( !requestDict )
	{
		requestDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
	}

	//set the streams
	CFMutableArrayRef requestStreams=CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
	require_action( requestStreams, exit, err = kNoMemoryErr );

	CFDictionaryRef  requestStreamDesc = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
            &kCFTypeDictionaryValueCallBacks);
	require_action(requestStreamDesc, exit, err = kNoMemoryErr);

	CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_ScreenLatencyMs), kAirPlayScreenLatencyWiredMs);
//	CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_ScreenLatencyMs), 100);
	CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_StreamConnectionID), 542165359262875319);
    CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_Type), kAirPlayStreamType_MainScreen);
//    CFDictionarySetValue(requestStreamDesc, CFSTR(kAirPlayKey_UUID),CFSTR("e5f7a68d-7b0f-4305-984b-974f677a150b"));
//    CFDictionarySetValue(requestStreamDesc, CFSTR(kAirPlayKey_UUID),CFSTR("6b8b4567327b23c6-643c9869-4873-af1b-19495cff2ae8944a625558ec"));
    char display_uuid [ 200 ];
    // __system_property_get("sys.shark.screen.uuid", display_uuid);
//    CFDictionarySetValue(requestStreamDesc, CFSTR(kAirPlayKey_UUID),CFSTR(display_uuid));
    CFDictionarySetCString( requestStreamDesc, CFSTR( kAirPlayKey_UUID ), display_uuid ,kSizeCString);
    CFArrayAppendValue( requestStreams, requestStreamDesc );

    //timestampInfo
	CFMutableArrayRef timestampInfo=CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
	require_action( timestampInfo, exit, err = kNoMemoryErr );

	//1.
	CFDictionaryRef  SubSu = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
            &kCFTypeDictionaryValueCallBacks);
	require_action(SubSu, exit, err = kNoMemoryErr);
	CFDictionarySetValue(SubSu, CFSTR(kAirPlayKey_Name),CFSTR("SubSu"));
	CFArrayAppendValue( timestampInfo, SubSu );
	//2.
	CFDictionaryRef  BePxT = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
            &kCFTypeDictionaryValueCallBacks);
	require_action(BePxT, exit, err = kNoMemoryErr);
	CFDictionarySetValue(BePxT, CFSTR(kAirPlayKey_Name),CFSTR("BePxT"));
	CFArrayAppendValue( timestampInfo, BePxT );
	//3.
	CFDictionaryRef  AfPxT = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
            &kCFTypeDictionaryValueCallBacks);
	require_action(AfPxT, exit, err = kNoMemoryErr);
	CFDictionarySetValue(AfPxT, CFSTR(kAirPlayKey_Name),CFSTR("AfPxT"));
	CFArrayAppendValue( timestampInfo, AfPxT );
	//4.
	CFDictionaryRef  BefEn = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
            &kCFTypeDictionaryValueCallBacks);
	require_action(BefEn, exit, err = kNoMemoryErr);
	CFDictionarySetValue(BefEn, CFSTR(kAirPlayKey_Name),CFSTR("BefEn"));
	CFArrayAppendValue( timestampInfo, BefEn );
	//5.
	CFDictionaryRef  EmEnc = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
            &kCFTypeDictionaryValueCallBacks);
	require_action(EmEnc, exit, err = kNoMemoryErr);
	CFDictionarySetValue(EmEnc, CFSTR(kAirPlayKey_Name),CFSTR("EmEnc"));
	CFArrayAppendValue( timestampInfo, EmEnc );

	CFDictionarySetValue(requestStreamDesc, CFSTR(kAirPlayProperty_TimestampInfo),timestampInfo);

	CFDictionarySetValue( requestDict, CFSTR( kAirPlayKey_Streams ), requestStreams );

	cpcc_ulog( kLogLevelTrace, "setupRequestDict = %@\n", requestDict );

//	//[Dictionary] Controller supported features.
	const uint8_t*      ptr;
	size_t              len;
    if (requestDict) {
        ptr = CFBinaryPlistV0Create(requestDict, &len, NULL);
        err = HTTPMessageSetBodyPtr(httpMessage, kMIMEType_AppleBinaryPlist, ptr, len);
    }

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Request **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	cpcc_ulog( kLogLevelTrace, "ScreenHTTPClientSendMessageSync \n");
	err = HTTPClientSendMessageSync( gHttpClient, httpMessage );
	require_noerr( err, exit );
	increaseSyncNumber();
	// Read the response header

	require_action( httpMessage->header.statusCode != 0, exit, err = kResponseErr );
	require_action( IsHTTPStatusCode_Success( httpMessage->header.statusCode ), exit, err = HTTPStatusToOSStatus( httpMessage->header.statusCode ) );

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Response **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	gScreenStarted = 1;
	//这里需通知timing结束
	AirPlayReceiverSetTimingNegotiateActive( (mAirPlayClientConnection->session),true);

	//需要读出screen receivePort 开始传送h264视频数据
	CFDictionaryRef responseDict = (CFDictionaryRef)CFBinaryPlistV0CreateWithData(httpMessage->bodyPtr, httpMessage->bodyOffset, &err);
	require_noerr( err, exit );
	cpcc_ulog( kLogLevelTrace, "setup-screen responseDict = %@\n", responseDict );

	CFArrayRef	responseStreams;
	CFIndex     streamIndex, streamCount;
	responseStreams = CFDictionaryGetCFArray(responseDict, CFSTR(kAirPlayKey_Streams), &err);
    streamCount = responseStreams ? CFArrayGetCount(responseStreams) : 0;
    CFDictionaryRef             responseStreamDesc;
    AirPlayStreamType           type;
    for (streamIndex = 0; streamIndex < streamCount; ++streamIndex) {
    	responseStreamDesc = CFArrayGetCFDictionaryAtIndex(responseStreams, streamIndex, &err);
        require_noerr(err, exit);

    	int64_t screenType=CFDictionaryGetInt64(responseStreamDesc,  CFSTR(kAirPlayKey_Type), &err);
    	require_noerr( err, exit );
    	gPeerScreenType = screenType;
    	cpcc_ulog( kLogLevelTrace, "peer screenType %d \n", screenType );

    	int64_t screenPortRemote = CFDictionaryGetInt64(responseStreamDesc, CFSTR(kAirPlayKey_Port_Data), &err);//车机侧session timingport
        require_noerr( err, exit );
        gPeerScreenPort = screenPortRemote;

    	AirPlayReceiverSessionControlSetScreenUrl(mAirPlayClientConnection->session, mAirPlayClientConnection->peerUrl, screenPortRemote);
        cpcc_ulog( kLogLevelTrace, "peer screenPort %d \n", screenPortRemote );

        type = (AirPlayStreamType) CFDictionaryGetInt64(responseStreamDesc, CFSTR(kAirPlayKey_Type), NULL);
        switch (type) {
            case kAirPlayStreamType_MainHighAudio:
            case kAirPlayStreamType_MainAudio:
            case kAirPlayStreamType_AltAudio:
            case kAirPlayStreamType_AuxInAudio:
            case kAirPlayStreamType_AuxOutAudio:
//                require_noerr(err, exit);
                break;
            case kAirPlayStreamType_MainScreen:
            case kAirPlayStreamType_AltScreen:
//                err = _ScreenSetup(session, requestStreamDesc, NULL);
                cpcc_ulog( kLogLevelTrace, "_ScreenSetup  %#m ",err);
                err = AirPlayReceiverSessionSetup( (mAirPlayClientConnection->session), requestDict,NULL);
                dispatch_async_f(inClient->httpClientQueue, SHARK_EVENT_SESSION_SCREEN_START, _CarPlayControlClientEvent);
                break;
            default:
            	cpcc_ulog( kLogLevelTrace,  "### Unsupported stream type: %d\n", type);
                break;
        }
    }


exit:
	if( err )	cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" failed    @ %N: %#m\n", inCommand, err );
	else		cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" completed @ %N\n", inCommand);

	if(requestDict)CFReleaseNullSafe(requestDict);
	if(requestStreams)CFReleaseNullSafe(requestStreams);
	CFReleaseNullSafe( httpMessage );

	return( err );
}


//===========================================================================================================================
//	_CarPlayControlClientDearDownScreen
//===========================================================================================================================

static OSStatus
	_CarPlayControlClientDearDownScreen(
		CarPlayControlClientRef inClient, CarPlayBonjourServiceRef inService, const char *inCommand )
{
	OSStatus			err;
	char *				rtspHostName = NULL;
	HTTPMessageRef		httpMessage = NULL;
	// Build the request

	err = HTTPMessageCreate( &httpMessage );
	require_noerr( err, exit );

	char	url[ 100 ];
	char	ipv6[ 100 ];
	memset(url,0,100);
	memcpy(url, mAirPlayClientConnection->peerUrl,100);
	int index=indexOf(url, 0, 100, "%", 0, 1, 0);
	//%usb0
	if(index>0)
	{
		strlcpy(ipv6,url,(index+1));
//		cpcc_ulog( kLogLevelTrace, "TinkerIPV6 %s\n", ipv6 );
	}else{
		strlcpy(ipv6,url,strlen(url));
	}

	asprintf( &rtspHostName, "%s%s%s%llu", "rtsp://", ipv6, "/",gMeSessionUUID);
	cpcc_ulog( kLogLevelTrace, "rtspHostName %s\n", rtspHostName );
	err = HTTPHeader_InitRequest( &httpMessage->header, kHTTPMethodString_TEARDOWN, rtspHostName, kRTSPVersionString_1pt1 );
	require_noerr( err, exit );

	//log for header
	cpcc_ulog( kLogLevelTrace, "TinkerHeader %s\n", httpMessage->header.buf );
	//CSeq
	char CSeq[32];
	snprintf( CSeq, sizeof(CSeq), "%d", m_SyncNumber );
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_CSeq, CSeq );
	require_noerr( err, exit );

	//User-Agent
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_UserAgent, kAirPlayUserAgentStr );
	require_noerr( err, exit );

	//Content-Type
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_ContentType, kMIMEType_AppleBinaryPlist );
	require_noerr( err, exit );

	//Payload data

	CFDictionaryRef			requestDict =NULL;
	if( !requestDict )
	{
		requestDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
	}

	//set the streams
	cpcc_ulog( kLogLevelTrace, "set the streams = %@\n", requestDict );
	CFMutableArrayRef requestStreams=CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
	require_action( requestStreams, exit, err = kNoMemoryErr );

	CFDictionaryRef  requestStreamDesc = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
            &kCFTypeDictionaryValueCallBacks);
	require_action(requestStreamDesc, exit, err = kNoMemoryErr);

    CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_Type), kAirPlayStreamType_MainScreen);
//    CFDictionarySetValue(requestStreamDesc, CFSTR(kAirPlayKey_UUID),CFSTR("e5f7a68d-7b0f-4305-984b-974f677a150b"));
//    CFDictionarySetValue(requestStreamDesc, CFSTR(kAirPlayKey_UUID),CFSTR("6b8b4567327b23c6-643c9869-4873-af1b-19495cff2ae8944a625558ec"));
    char display_uuid [ 200 ];
    // __system_property_get("sys.shark.screen.uuid", display_uuid);
    CFDictionarySetCString( requestStreamDesc, CFSTR( kAirPlayKey_UUID ), display_uuid ,kSizeCString);
    CFArrayAppendValue( requestStreams, requestStreamDesc );




	CFDictionarySetValue( requestDict, CFSTR( kAirPlayKey_Streams ), requestStreams );

	cpcc_ulog( kLogLevelTrace, "TearDownRequestDict = %@\n", requestDict );

//	//[Dictionary] Controller supported features.
	const uint8_t*      ptr;
	size_t              len;
    if (requestDict) {
        ptr = CFBinaryPlistV0Create(requestDict, &len, NULL);
        err = HTTPMessageSetBodyPtr(httpMessage, kMIMEType_AppleBinaryPlist, ptr, len);
    }

    Boolean		done = true;
    AirPlayReceiverSessionTearDown( (mAirPlayClientConnection->session), requestDict, kNoErr, &done );

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Request **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	cpcc_ulog( kLogLevelTrace, "ScreenTearDown HTTPClientSendMessageSync \n");
	err = HTTPClientSendMessageSync( gHttpClient, httpMessage );
	require_noerr( err, exit );
	increaseSyncNumber();
	// Read the response header

	require_action( httpMessage->header.statusCode != 0, exit, err = kResponseErr );
	require_action( IsHTTPStatusCode_Success( httpMessage->header.statusCode ), exit, err = HTTPStatusToOSStatus( httpMessage->header.statusCode ) );

	cpcc_ulog( kLogLevelTrace, "**********ScreenTearDown  CarPlayControl Response **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	//同时需要对自己的screen tear down
	gScreenStarted = 0;
	cpcc_ulog( kLogLevelTrace, "**********ScreenTearDown  CarPlayControl Response AirPlayReceiverSessionTearDown Begin**********\n" );
//	AirPlayReceiverSessionTearDown( (mAirPlayClientConnection->session), requestDict, kNoErr, &done );
	gPeerTimingPort = 0;
	gPeerScreenPort = 0;
	cpcc_ulog( kLogLevelTrace, "**********ScreenTearDown  CarPlayControl Response AirPlayReceiverSessionTearDown**********\n" );

exit:
	if( err )	cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" failed    @ %N: %#m\n", inCommand, err );
	else		cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" completed @ %N\n", inCommand);

	if(requestDict)CFReleaseNullSafe(requestDict);
	if(requestStreams)CFReleaseNullSafe(requestStreams);
	CFReleaseNullSafe( httpMessage );

	return( err );
}



//===========================================================================================================================
//	_CarPlayControlClientDearDownAudio
//===========================================================================================================================

static OSStatus
	_CarPlayControlClientDearDownAudio(
		CarPlayControlClientRef inClient, CarPlayBonjourServiceRef inService, const char *inCommand )
{
	OSStatus			err;
	char *				rtspHostName = NULL;
	HTTPMessageRef		httpMessage = NULL;

	// Build the request

	err = HTTPMessageCreate( &httpMessage );
	require_noerr( err, exit );

	char	url[ 100 ];
	char	ipv6[ 100 ];
	memset(url,0,100);
	memcpy(url, mAirPlayClientConnection->peerUrl,100);
	int index=indexOf(url, 0, 100, "%", 0, 1, 0);
	//%usb0
	if(index>0)
	{
		strlcpy(ipv6,url,(index+1));
//		cpcc_ulog( kLogLevelTrace, "TinkerIPV6 %s\n", ipv6 );
	}else{
		strlcpy(ipv6,url,strlen(url));
	}

	asprintf( &rtspHostName, "%s%s%s%llu", "rtsp://", ipv6, "/",gMeSessionUUID);
//	cpcc_ulog( kLogLevelTrace, "rtspHostName %s\n", rtspHostName );
	err = HTTPHeader_InitRequest( &httpMessage->header, kHTTPMethodString_TEARDOWN, rtspHostName, kRTSPVersionString_1pt1 );
	require_noerr( err, exit );

	//log for header
//	cpcc_ulog( kLogLevelTrace, "TinkerHeader %s\n", httpMessage->header.buf );
	//CSeq
	char CSeq[32];
	snprintf( CSeq, sizeof(CSeq), "%d", m_SyncNumber );
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_CSeq, CSeq );
	require_noerr( err, exit );

	//User-Agent
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_UserAgent, kAirPlayUserAgentStr );
	require_noerr( err, exit );

	//Content-Type
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_ContentType, kMIMEType_AppleBinaryPlist );
	require_noerr( err, exit );

	//Payload data

	CFDictionaryRef			requestDict =NULL;
	if( !requestDict )
	{
		requestDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
	}

	//set the streams
	CFMutableArrayRef requestStreams=CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
	require_action( requestStreams, exit, err = kNoMemoryErr );

	CFDictionaryRef  requestStreamDesc = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
            &kCFTypeDictionaryValueCallBacks);
	require_action(requestStreamDesc, exit, err = kNoMemoryErr);


	AirPlayModeState * modeState = AirPlayReceiverSessionControlGetAppState((mAirPlayClientConnection->session));
	int targetChannel = modeState->targetStopChannel;
	if( targetChannel == AUDIO_CHANNEL_STOP )
	{
		goto exit;
	}
	if( targetChannel == AUDIO_CHANNEL_MEDIA )
	{
		//媒体声音
		if( gHomeKitEnable == 1 )
		{
			CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_StreamConnectionID), 9209106407472805277);
		}

	    CFDictionarySetValue(requestStreamDesc, CFSTR(kAirPlayKey_AudioType), CFSTR(kAirPlayAudioType_Media));
	    CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_Type), kAirPlayStreamType_MainAudio);

	}
	else if( targetChannel == AUDIO_CHANNEL_PHONE ){
		if( gHomeKitEnable == 1 )
		{
			CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_StreamConnectionID), 9209106407472805278);
		}

	    CFDictionarySetValue(requestStreamDesc, CFSTR(kAirPlayKey_AudioType), CFSTR(kAirPlayAudioType_Telephony));
	    CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_Type), kAirPlayStreamType_MainAudio);
	    CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_AudioLatencyMs), 32);
	}
	else if( targetChannel == AUDIO_CHANNEL_SPEECH ){
		if( gHomeKitEnable == 1 )
		{
			CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_StreamConnectionID), 9209106407472805279);
		}

	    CFDictionarySetValue(requestStreamDesc, CFSTR(kAirPlayKey_AudioType), CFSTR(kAirPlayAudioType_SpeechRecognition));
	    CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_Type), kAirPlayStreamType_MainAudio);
	}
	else if( targetChannel == AUDIO_CHANNEL_NAVIGATION ){
		usleep( 500 * 1000);
		if( gHomeKitEnable == 1 )
		{
			CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_StreamConnectionID), 9209106407472805280);
		}

	    CFDictionarySetValue(requestStreamDesc, CFSTR(kAirPlayKey_AudioType), CFSTR(kAirPlayAudioType_Default));
	    CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_Type), kAirPlayStreamType_AltAudio);
	}

    CFArrayAppendValue( requestStreams, requestStreamDesc );
	CFDictionarySetValue( requestDict, CFSTR( kAirPlayKey_Streams ), requestStreams );

	cpcc_ulog( kLogLevelTrace, "TearDownAudioRequestDict = %@\n", requestDict );

//	//[Dictionary] Controller supported features.
	const uint8_t*      ptr;
	size_t              len;
    if (requestDict) {
        ptr = CFBinaryPlistV0Create(requestDict, &len, NULL);
        err = HTTPMessageSetBodyPtr(httpMessage, kMIMEType_AppleBinaryPlist, ptr, len);
    }

	//同时需要对自己的audio tear down
	Boolean		done = true;
	cpcc_ulog( kLogLevelTrace, "**********AudioTearDown  CarPlayControl Response AirPlayReceiverSessionTearDown Begin**********\n" );
	AirPlayReceiverSessionTearDown( (mAirPlayClientConnection->session), requestDict, kNoErr, &done );
	cpcc_ulog( kLogLevelTrace, "**********AudioTearDown  CarPlayControl Response AirPlayReceiverSessionTearDown**********\n" );


	cpcc_ulog( kLogLevelTrace, "********** TearDownAudioCarPlayControl Request **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	cpcc_ulog( kLogLevelTrace, "TearDownAudio HTTPClientSendMessageSync \n");
	err = HTTPClientSendMessageSync( gHttpClient, httpMessage );
	require_noerr( err, exit );
	increaseSyncNumber();
	// Read the response header

	require_action( httpMessage->header.statusCode != 0, exit, err = kResponseErr );
	require_action( IsHTTPStatusCode_Success( httpMessage->header.statusCode ), exit, err = HTTPStatusToOSStatus( httpMessage->header.statusCode ) );

	cpcc_ulog( kLogLevelTrace, "**********AudioTearDown  CarPlayControl Response **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	modeState->lastChannel = targetChannel;
	dispatch_async_f( gCarPlayClient->httpClientQueue, SHARK_EVENT_SESSION_MODES_CHANGED_TEARDOWN, _CarPlayControlEnqueueTask );

exit:
	if( err )	cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" failed    @ %N: %#m\n", inCommand, err );
	else		cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" completed @ %N\n", inCommand);

	if( requestDict )CFReleaseNullSafe(requestDict);
	if( requestStreams )CFReleaseNullSafe(requestStreams);
	CFReleaseNullSafe( httpMessage );

	return( err );
}


//===========================================================================================================================
//	_CarPlayControlClientRtspSetupAudio
//===========================================================================================================================

static OSStatus
	_CarPlayControlClientRtspSetupAudio(
		CarPlayControlClientRef inClient, CarPlayBonjourServiceRef inService, const char *inCommand )
{
	OSStatus			err;
	char *				rtspHostName = NULL;
	HTTPMessageRef		httpMessage = NULL;

	// Build the request

	err = HTTPMessageCreate( &httpMessage );
	require_noerr( err, exit );

	char	url[ 100 ];
	char	ipv6[ 100 ];
	memset(url,0,100);
	memcpy(url, mAirPlayClientConnection->peerUrl,100);
	int index=indexOf(url, 0, 100, "%", 0, 1, 0);
	//%usb0
	if(index>0)
	{
		strlcpy(ipv6,url,(index+1));
//		cpcc_ulog( kLogLevelTrace, "TinkerIPV6 %s\n", ipv6 );
	}else{
		strlcpy(ipv6,url,strlen(url));
	}

	asprintf( &rtspHostName, "%s%s%s%llu", "rtsp://", ipv6, "/",gMeSessionUUID);
//	cpcc_ulog( kLogLevelTrace, "rtspHostName %s\n", rtspHostName );
	err = HTTPHeader_InitRequest( &httpMessage->header, kHTTPMethodString_SETUP, rtspHostName, kRTSPVersionString_1pt1 );
	require_noerr( err, exit );

	//log for header
//	cpcc_ulog( kLogLevelTrace, "TinkerHeader %s\n", httpMessage->header.buf );
	//CSeq
	char CSeq[32];
	snprintf( CSeq, sizeof(CSeq), "%d", m_SyncNumber );
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_CSeq, CSeq );
	require_noerr( err, exit );

	//User-Agent
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_UserAgent, kAirPlayUserAgentStr );
	require_noerr( err, exit );

	//Content-Type
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_ContentType, kMIMEType_AppleBinaryPlist );
	require_noerr( err, exit );

	//Payload data

	CFDictionaryRef			requestDict =NULL;
	if( !requestDict )
	{
		requestDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
	}

	//set the streams
	CFMutableArrayRef requestStreams=CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
	require_action( requestStreams, exit, err = kNoMemoryErr );

	CFDictionaryRef  requestStreamDesc = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
            &kCFTypeDictionaryValueCallBacks);
	require_action(requestStreamDesc, exit, err = kNoMemoryErr);

	CFDictionaryRef  vocoderInfoDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
            &kCFTypeDictionaryValueCallBacks);
	require_action(vocoderInfoDict, exit, err = kNoMemoryErr);

	AirPlayModeState * modeState = AirPlayReceiverSessionControlGetAppState((mAirPlayClientConnection->session));
	int targetChannel = modeState->targetPlayChannel;
	if( targetChannel == AUDIO_CHANNEL_MEDIA )
	{
		//媒体声音
		void * multimediaDict = AirPlayReceiverSessionControlGetAudioFormat(mAirPlayClientConnection->session, AUDIO_CHANNEL_MEDIA);
		int64_t audioOutputFormat = kAirPlayAudioFormat_PCM_48KHz_16Bit_Stereo;
		int64_t audioLatencyMs = 32;
		if( multimediaDict != NULL )
		{
			CFDictionaryRef mediaDict = (CFDictionaryRef )multimediaDict;
			audioOutputFormat = CFDictionaryGetInt64( mediaDict, CFSTR( kAirPlayKey_AudioOutputFormats ) , &err);
			cpcc_ulog( kLogLevelTrace, "audio setupRequestDict media audioOutputFormat = %ld\n", audioOutputFormat );
			audioLatencyMs = CFDictionaryGetInt64( mediaDict, CFSTR( kAirPlayKey_AudioLatencyMs ) , &err);
			cpcc_ulog( kLogLevelTrace, "audio setupRequestDict media audioLatencyMs = %ld\n", audioLatencyMs );
		}

		if( gHomeKitEnable == 1 )
		{
			CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_StreamConnectionID), 9209106407472805277);
		}
		CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_AudioFormat), audioOutputFormat);
	    CFDictionarySetValue(requestStreamDesc, CFSTR(kAirPlayKey_AudioType), CFSTR(kAirPlayAudioType_Media));
	    CFDictionarySetBoolean(requestStreamDesc, CFSTR(kAirPlayKey_SupportsHighAccuracyTimestamps), kCFLBooleanTrue);
	    CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_Type), kAirPlayStreamType_MainAudio);
	    CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_AudioLatencyMs), 32);
//	    CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_AudioLatencyMs), audioLatencyMs);

	}
	else if( targetChannel == AUDIO_CHANNEL_PHONE ){
//		CFDictionarySetDouble( vocoderInfoDict, CFSTR( kAirPlayVocoderInfoKey_SampleRate ), 8000 );
		CFDictionarySetValue( requestStreamDesc, CFSTR( kAirPlayKey_VocoderInfo ), vocoderInfoDict );

		void * telephoneDict = AirPlayReceiverSessionControlGetAudioFormat(mAirPlayClientConnection->session, AUDIO_CHANNEL_PHONE);
		int64_t audioOutputFormat = kAirPlayAudioFormat_PCM_16KHz_16Bit_Mono;
		int64_t audioLatencyMs = 50;
		if( telephoneDict != NULL )
		{
			CFDictionaryRef phoneDict = (CFDictionaryRef )telephoneDict;
			audioOutputFormat = CFDictionaryGetInt64( phoneDict, CFSTR( kAirPlayKey_AudioOutputFormats ) , &err);
			cpcc_ulog( kLogLevelTrace, "audio setupRequestDict phone audioOutputFormat = %ld\n", audioOutputFormat );
			audioLatencyMs = CFDictionaryGetInt64( phoneDict, CFSTR( kAirPlayKey_AudioLatencyMs ) , &err);
		}

		if( gHomeKitEnable == 1 )
		{
			CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_StreamConnectionID), 9209106407472805278);
		}

		CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_AudioFormat), audioOutputFormat);
	    CFDictionarySetValue(requestStreamDesc, CFSTR(kAirPlayKey_AudioType), CFSTR(kAirPlayAudioType_Telephony));
	    CFDictionarySetBoolean(requestStreamDesc, CFSTR(kAirPlayKey_SupportsHighAccuracyTimestamps), kCFLBooleanTrue);
	    CFDictionarySetBoolean(requestStreamDesc, CFSTR(kAirPlayKey_Input), kCFLBooleanTrue);
	    CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_Type), kAirPlayStreamType_MainAudio);
	    CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_AudioLatencyMs), audioLatencyMs);
	}
	else if( targetChannel == AUDIO_CHANNEL_SPEECH ){
//		CFDictionarySetDouble( vocoderInfoDict, CFSTR( kAirPlayVocoderInfoKey_SampleRate ), 8000 );
//		CFDictionarySetValue( requestStreamDesc, CFSTR( kAirPlayKey_VocoderInfo ), vocoderInfoDict );

		void * speechDict = AirPlayReceiverSessionControlGetAudioFormat(mAirPlayClientConnection->session, AUDIO_CHANNEL_SPEECH);
		int64_t audioOutputFormat = kAirPlayAudioFormat_PCM_16KHz_16Bit_Mono;
		int64_t audioLatencyMs = 50;
		if( speechDict != NULL )
		{
			CFDictionaryRef speechRecognizeDict = (CFDictionaryRef )speechDict;
			audioOutputFormat = CFDictionaryGetInt64( speechRecognizeDict, CFSTR( kAirPlayKey_AudioOutputFormats ) , &err);
			cpcc_ulog( kLogLevelTrace, "audio setupRequestDict speech audioOutputFormat = %ld\n", audioOutputFormat );
			audioLatencyMs = CFDictionaryGetInt64( speechRecognizeDict, CFSTR( kAirPlayKey_AudioLatencyMs ) , &err);
		}

		if( gHomeKitEnable == 1 )
		{
			CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_StreamConnectionID), 9209106407472805279);
		}

		CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_AudioFormat), audioOutputFormat);
	    CFDictionarySetValue(requestStreamDesc, CFSTR(kAirPlayKey_AudioType), CFSTR(kAirPlayAudioType_SpeechRecognition));
	    CFDictionarySetBoolean(requestStreamDesc, CFSTR(kAirPlayKey_SupportsHighAccuracyTimestamps), kCFLBooleanTrue);
	    CFDictionarySetBoolean(requestStreamDesc, CFSTR(kAirPlayKey_Input), kCFLBooleanTrue);
	    CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_Type), kAirPlayStreamType_MainAudio);
	    CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_AudioLatencyMs), audioLatencyMs);
	}
	else if( targetChannel == AUDIO_CHANNEL_NAVIGATION ){
		//导航声音
		cpcc_ulog( kLogLevelTrace, "audio setupRequestDict navi audio setup.\n" );
		void * altDict = AirPlayReceiverSessionControlGetAudioFormat(mAirPlayClientConnection->session, AUDIO_CHANNEL_NAVIGATION);
		int64_t audioOutputFormat = kAirPlayAudioFormat_PCM_48KHz_16Bit_Stereo;
		int64_t audioLatencyMs = 120;
		if( altDict != NULL )
		{
			CFDictionaryRef naviDict = (CFDictionaryRef )altDict;
			audioOutputFormat = CFDictionaryGetInt64( naviDict, CFSTR( kAirPlayKey_AudioOutputFormats ) , &err);
			cpcc_ulog( kLogLevelTrace, "audio setupRequestDict navi audioOutputFormat = %ld\n", audioOutputFormat );
			audioLatencyMs = CFDictionaryGetInt64( naviDict, CFSTR( kAirPlayKey_AudioLatencyMs ) , &err);
		}

		if( gHomeKitEnable == 1 )
		{
			CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_StreamConnectionID), 9209106407472805280);
		}
		CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_AudioFormat), audioOutputFormat);
		cpcc_ulog( kLogLevelTrace, "set audioOutputFormat = %ld\n", audioOutputFormat );

		int64_t audioFomats = CFDictionaryGetInt64(requestStreamDesc, CFSTR(kAirPlayKey_AudioFormat), &err);
		cpcc_ulog( kLogLevelTrace, "check audioOutputFormat = %ld\n", audioFomats );

	    CFDictionarySetValue(requestStreamDesc, CFSTR(kAirPlayKey_AudioType), CFSTR(kAirPlayAudioType_Default));
	    CFDictionarySetBoolean(requestStreamDesc, CFSTR(kAirPlayKey_SupportsHighAccuracyTimestamps), kCFLBooleanTrue);
	    CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_Type), kAirPlayStreamType_AltAudio);
	    CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_AudioLatencyMs), audioLatencyMs);
	}

    CFArrayAppendValue( requestStreams, requestStreamDesc );


	CFDictionarySetValue( requestDict, CFSTR( kAirPlayKey_Streams ), requestStreams );

//	cpcc_ulog( kLogLevelTrace, "audio setupRequestDict = %@\n", requestDict );
	int64_t receivePort = 0;
	//发送请求前，需要设置
	if( targetChannel == AUDIO_CHANNEL_PHONE || targetChannel == AUDIO_CHANNEL_SPEECH){
//		CFDictionaryRef phoneResponseDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
//		err = AirPlayReceiverSessionSetup( (mAirPlayClientConnection->session), requestDict,&phoneResponseDict);
//		cpcc_ulog( kLogLevelTrace, "audio phoneResponseDict = %@\n", phoneResponseDict );
//		CFArrayRef phoneResponseStreams = CFDictionaryGetCFArray(phoneResponseDict, CFSTR(kAirPlayKey_Streams), &err);
//		CFDictionaryRef phoneResponseStreamDesc = CFArrayGetCFDictionaryAtIndex(phoneResponseStreams, 0, &err);
//		receivePort = CFDictionaryGetInt64(phoneResponseStreamDesc, CFSTR(kAirPlayKey_Port_Data), &err);

		AirPlayReceiverSessionControlSetAudioReceiverSocket((mAirPlayClientConnection->session),&receivePort );
		cpcc_ulog( kLogLevelTrace, "audio phone receivePort = %d\n", receivePort );

		//重新组成数据包
		CFDictionaryRemoveValue( requestDict, CFSTR( kAirPlayKey_Streams ) );
		CFArrayRemoveAllValues( requestStreams );
		CFDictionarySetInt64( requestStreamDesc, CFSTR( kAirPlayKey_Port_Data ), receivePort );
		CFArrayAppendValue( requestStreams, requestStreamDesc );
		CFDictionarySetValue( requestDict, CFSTR( kAirPlayKey_Streams ), requestStreams );
	}
	cpcc_ulog( kLogLevelTrace, "audio setupRequestDict before send = %@\n", requestDict );

//	//[Dictionary] Controller supported features.
	const uint8_t*      ptr;
	size_t              len;
    if (requestDict) {
        ptr = CFBinaryPlistV0Create(requestDict, &len, NULL);
        err = HTTPMessageSetBodyPtr(httpMessage, kMIMEType_AppleBinaryPlist, ptr, len);
    }

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Request **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	cpcc_ulog( kLogLevelTrace, "AudioHTTPClientSendMessageSync \n");
	err = HTTPClientSendMessageSync( gHttpClient, httpMessage );
	require_noerr( err, exit );
	increaseSyncNumber();
	// Read the response header

	require_action( httpMessage->header.statusCode != 0, exit, err = kResponseErr );
	require_action( IsHTTPStatusCode_Success( httpMessage->header.statusCode ), exit, err = HTTPStatusToOSStatus( httpMessage->header.statusCode ) );

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Response **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	//需要读出audio receivePort 开始传送pcm音频数据
	CFDictionaryRef responseDict = (CFDictionaryRef)CFBinaryPlistV0CreateWithData(httpMessage->bodyPtr, httpMessage->bodyOffset, &err);
	require_noerr( err, exit );
	cpcc_ulog( kLogLevelTrace, "setup-audio responseDict = %@\n", responseDict );

	CFArrayRef	responseStreams;
	CFIndex     streamIndex, streamCount;
	responseStreams = CFDictionaryGetCFArray(responseDict, CFSTR(kAirPlayKey_Streams), &err);
    streamCount = responseStreams ? CFArrayGetCount(responseStreams) : 0;
    CFDictionaryRef             responseStreamDesc;
    AirPlayStreamType           type;
    for (streamIndex = 0; streamIndex < streamCount; ++streamIndex) {
    	responseStreamDesc = CFArrayGetCFDictionaryAtIndex(responseStreams, streamIndex, &err);
        require_noerr(err, exit);

    	int64_t audioType=CFDictionaryGetInt64(responseStreamDesc,  CFSTR(kAirPlayKey_Type), &err);
    	require_noerr( err, exit );
    	gPeerAudioType = audioType;
    	cpcc_ulog( kLogLevelTrace, "peer audioType %d \n", audioType );

    	int64_t audioPortRemote = CFDictionaryGetInt64(responseStreamDesc, CFSTR(kAirPlayKey_Port_Data), &err);//车机侧session timingport
        require_noerr( err, exit );
        gPeerAudioPort = audioPortRemote;
    	char strAudioPort[100];
    	snprintf( strAudioPort, sizeof(strAudioPort), "%d", gPeerAudioPort );
        // __system_property_set("sys.shark.session.audioport", strAudioPort);
        cpcc_ulog( kLogLevelTrace, "peer audioPort %d \n", audioPortRemote );

        //声音通道切
        type = (AirPlayStreamType) CFDictionaryGetInt64(responseStreamDesc, CFSTR(kAirPlayKey_Type), NULL);
        switch (type) {
            case kAirPlayStreamType_MainHighAudio:
            case kAirPlayStreamType_MainAudio:
            case kAirPlayStreamType_AltAudio:
            case kAirPlayStreamType_AuxInAudio:
            case kAirPlayStreamType_AuxOutAudio:
                cpcc_ulog( kLogLevelTrace, "_AudioSetup  %#m ",err);

                CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_Port_Data), audioPortRemote);
                if(receivePort > 0)
                {
                	CFDictionarySetInt64(requestStreamDesc, CFSTR(kAirPlayKey_Port_Data_RECV), receivePort);
                };

                CFArrayRemoveAllValues(requestStreams);
                CFArrayAppendValue( requestStreams, requestStreamDesc );
                CFDictionaryRemoveValue(requestDict, CFSTR( kAirPlayKey_Streams ));
                CFDictionarySetValue( requestDict, CFSTR( kAirPlayKey_Streams ), requestStreams );

                cpcc_ulog( kLogLevelTrace, "setup-audio self loopback  requestDict= %@\n", requestDict );
                err = AirPlayReceiverSessionSetup( (mAirPlayClientConnection->session), requestDict,NULL);
                dispatch_async_f(inClient->httpClientQueue, SHARK_EVENT_SESSION_AUDIO_START, _CarPlayControlClientEvent);
                break;
            case kAirPlayStreamType_MainScreen:
            case kAirPlayStreamType_AltScreen:
                break;
            default:
            	cpcc_ulog( kLogLevelTrace,  "### Unsupported stream type: %d\n", type);
                break;
        }
    }

exit:
	if( err )	cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" failed    @ %N: %#m\n", inCommand, err );
	else		cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" completed @ %N\n", inCommand);

	if(requestDict)CFReleaseNullSafe(requestDict);
	if(requestStreams)CFReleaseNullSafe(requestStreams);
	if(requestStreamDesc)CFReleaseNullSafe(requestStreamDesc);
	if(vocoderInfoDict)CFReleaseNullSafe(vocoderInfoDict);
	CFReleaseNullSafe( httpMessage );

	return( err );
}


//===========================================================================================================================
//	_HandlePairVerifyHomeKitCompletion
//===========================================================================================================================

static void	_HandlePairVerifyHomeKitCompletion( )
{
	cpcc_ulog( kLogLevelWarning, "Pair-verify  _HandlePairVerifyHomeKitCompletion \n" );
	OSStatus                   err;
    NetTransportDelegate        delegate;
    uint8_t                     readKey[ 32 ], writeKey[ 32 ];

    err = PairingSessionDeriveKey(mAirPlayClientConnection->pairVerifySessionHomeKit, kAirPlayPairingControlKeySaltPtr, kAirPlayPairingControlKeySaltLen,
    		kAirPlayPairingControlKeyReadInfoPtr, kAirPlayPairingControlKeyReadInfoLen, sizeof( readKey ), readKey);
    require_noerr(err, exit);

    err = PairingSessionDeriveKey( mAirPlayClientConnection->pairVerifySessionHomeKit, kAirPlayPairingControlKeySaltPtr, kAirPlayPairingControlKeySaltLen,
    		kAirPlayPairingControlKeyWriteInfoPtr, kAirPlayPairingControlKeyWriteInfoLen, sizeof( writeKey ), writeKey);
    require_noerr(err, exit);

	err = NetTransportChaCha20Poly1305Configure( &delegate, cpcc_http_ucat(), readKey, NULL, writeKey, NULL );
	require_noerr( err, exit );
	MemZeroSecure( readKey, sizeof( readKey ) );
	MemZeroSecure( writeKey, sizeof( writeKey ) );
	HTTPClientSetTransportDelegate(gHttpClient, &delegate);

	cpcc_ulog( kLogLevelWarning, "Pair-verify  succeeded\n" );

exit:
	if( err )
	{
		ForgetCF(&mAirPlayClientConnection->pairVerifySessionHomeKit);
		cpcc_ulog( kLogLevelWarning, "### Pair-verify completion failed: %#m\n", err );
	}
}

//===========================================================================================================================
//	_CarPlayControlClientPairVerify2
//===========================================================================================================================

static OSStatus
	_CarPlayControlClientPairVerify2(
		CarPlayControlClientRef inClient, CarPlayBonjourServiceRef inService, const char *inCommand)
{
	HTTPStatus		    status;
	OSStatus			err;
	HTTPMessageRef		httpMessage = NULL;

	cpcc_ulog( kLogLevelNotice, "CarPlayControl pair-verify step2 \n" );

	// Build the request

	err = HTTPMessageCreate( &httpMessage );
	require_noerr( err, exit );

	char url[32];
	snprintf( url, sizeof(url), "/pair-verify", "" );
	err = HTTPHeader_InitRequest( &httpMessage->header, kHTTPMethodString_POST, url, kRTSPVersionString_1pt1 );
	require_noerr( err, exit );

	//CSeq
	char CSeq[32];
	snprintf( CSeq, sizeof(CSeq), "%d", m_SyncNumber );
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_CSeq, CSeq );
	require_noerr( err, exit );

	//User-Agent
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_UserAgent, kAirPlayUserAgentStr );
	require_noerr( err, exit );


	//Content-Type
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_ContentType, kMIMEType_Binary );
	require_noerr( err, exit );

	//"X-Apple-AbsoluteTime" : "701686240",
	err = HTTPHeader_AddField( &httpMessage->header, "X-Apple-AbsoluteTime", "701686240" );
	require_noerr( err, exit );

	//"X-Apple-Client-Name" : "clare的 iPhone",
	err = HTTPHeader_AddField( &httpMessage->header, "X-Apple-Client-Name", gOEMBrand );
	require_noerr( err, exit );

	//"X-Apple-HKP" : "2",
	err = HTTPHeader_AddField( &httpMessage->header, "X-Apple-HKP", "2" );
	require_noerr( err, exit );

	//"X-Apple-PD" : "1"
	err = HTTPHeader_AddField( &httpMessage->header, "X-Apple-PD", "1" );
	require_noerr( err, exit );

	//Payload data
	uint8_t *				outputPtr	= NULL;
	size_t					outputLen	= 0;
	Boolean					done;

	HTTPMessageSetBodyPtr( httpMessage, kMIMEType_Binary, gCacheBodyPtr, gCacheBodyOffset );
	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Request **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	// send the request

	err = HTTPClientSendMessageSync( gHttpClient, httpMessage );
	require_noerr( err, exit );
	increaseSyncNumber();

	// Read the response header
	if(!IsHTTPStatusCode_Success( httpMessage->header.statusCode )){
		PairingSessionReset(mAirPlayClientConnection->pairVerifySessionHomeKit);
	}
	require_action( httpMessage->header.statusCode != 0, exit, err = kResponseErr );
	require_action( IsHTTPStatusCode_Success( httpMessage->header.statusCode ), exit, err = HTTPStatusToOSStatus( httpMessage->header.statusCode ) );

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Response **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	//解析HTTP Message
	uint8_t *  responseBodyPtr    = httpMessage->bodyPtr;
	size_t     responseBodyOffset = httpMessage->bodyOffset;
	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Response bodyOffset: %d \n", responseBodyOffset);
	PairingSessionExchange(mAirPlayClientConnection->pairVerifySessionHomeKit,responseBodyPtr,responseBodyOffset, &outputPtr, &outputLen,&done);

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl pair-verify step2 finish: %d \n", outputLen);

	if( done )
	{
		_HandlePairVerifyHomeKitCompletion();
	}

	if(gCacheBodyPtr)
	{
		CFReleaseNullSafe( gCacheBodyPtr );
	}
	gCacheBodyOffset=0;
	//SharkCarPlay
	if( done )
	{
		dispatch_async_f(inClient->httpClientQueue, SHARK_EVENT_PAIR_VERIFY2, _CarPlayControlClientEvent);
	}
	else
	{
		remove( "/data/shark/default.keychain" );
		cpcc_ulog( kLogLevelTrace, "********** CarPlayControl pair-verify step2 failed,reboot android.\n");
		system("reboot");
	}



exit:
	if( err )	cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" failed    @ %N: %#m\n", inCommand, err );
	else		cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" completed @ %N\n", inCommand);

	CFReleaseNullSafe( httpMessage );
	return( err );
}


//===========================================================================================================================
//	_CarPlayControlClientPairVerify
//===========================================================================================================================

static OSStatus
	_CarPlayControlClientPairVerify(
		CarPlayControlClientRef inClient, CarPlayBonjourServiceRef inService, const char *inCommand )
{
	HTTPStatus		    status;
	OSStatus			err;
	const char *		hostName = NULL;
	char *				hostNameWithInterfaceNdx = NULL;
	uint16_t			port = 0;
	uint32_t			interfaceNdx = 0;
	HTTPMessageRef		httpMessage = NULL;

	// Get the service address
	cpcc_ulog( kLogLevelNotice, "CarPlayControl pair-verify step1 \n" );
	if( inService )
	{
		err = CarPlayBonjourServiceGetAddress( inService, &hostName, &port, &interfaceNdx );
		require_noerr( err, exit );
		if( strlen ( gBonjourIPAddress ) > 0 )
		{
			asprintf( &hostNameWithInterfaceNdx, "%s%s",gBonjourIPAddress,"%usb0" );
		}else{
			asprintf( &hostNameWithInterfaceNdx, "%s%%%u", hostName, (unsigned)interfaceNdx );
		}
	}
	else {
		asprintf( &hostNameWithInterfaceNdx, "%s%s",gBonjourIPAddress,"%usb0" );
		port = gBonjourPort;
	}

	// Connect to the controller

//	cpcc_ulog( kLogLevelNotice, "CarPlayControl connecting to %s on port %d\n", hostNameWithInterfaceNdx, (int) port );

	if(!gHttpClient)
	{
		err = _CreateHTTPClientRef(hostNameWithInterfaceNdx, port, inClient->httpQueue);
	}

	// Build the request

	err = HTTPMessageCreate( &httpMessage );
	require_noerr( err, exit );

	char url[32];
	snprintf( url, sizeof(url), "/pair-verify", "" );
	err = HTTPHeader_InitRequest( &httpMessage->header, kHTTPMethodString_POST, url, kRTSPVersionString_1pt1 );
	require_noerr( err, exit );

	//CSeq
	char CSeq[32];
	snprintf( CSeq, sizeof(CSeq), "%d", m_SyncNumber );
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_CSeq, CSeq );
	require_noerr( err, exit );

	//User-Agent
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_UserAgent, kAirPlayUserAgentStr );
	require_noerr( err, exit );

	//Content-Type
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_ContentType, kMIMEType_Binary );
	require_noerr( err, exit );

	//"X-Apple-AbsoluteTime" : "701686240",
	err = HTTPHeader_AddField( &httpMessage->header, "X-Apple-AbsoluteTime", "701686240" );
	require_noerr( err, exit );

	//"X-Apple-Client-Name" : "clare的 iPhone",
	err = HTTPHeader_AddField( &httpMessage->header, "X-Apple-Client-Name", gOEMBrand );
	require_noerr( err, exit );

	//"X-Apple-HKP" : "2",
	err = HTTPHeader_AddField( &httpMessage->header, "X-Apple-HKP", "2" );
	require_noerr( err, exit );

	//"X-Apple-PD" : "1"
	err = HTTPHeader_AddField( &httpMessage->header, "X-Apple-PD", "1" );
	require_noerr( err, exit );

	//Payload data
	err = PairingSessionCreate( &mAirPlayClientConnection->pairVerifySessionHomeKit, NULL, kPairingSessionType_VerifyClient );
	require_noerr_action( err, exit, status = kHTTPStatus_InternalServerError );

	PairingSessionReset(mAirPlayClientConnection->pairVerifySessionHomeKit);

	PairingSessionSetKeychainInfo_AirPlay( mAirPlayClientConnection->pairVerifySessionHomeKit );
	PairingSessionSetLogging( mAirPlayClientConnection->pairVerifySessionHomeKit, cpcc_http_ucat() );

	char	deviceId[ 40 ];
	// __system_property_get("sys.xq.product.deviceid", deviceId);

	err = PairingSessionSetIdentifier( mAirPlayClientConnection->pairVerifySessionHomeKit, deviceId, kSizeCString );
	require_noerr_action( err, exit, status = kHTTPStatus_InternalServerError );

	uint8_t *				outputPtr	= NULL;
	size_t					outputLen	= 0;
	Boolean					done;
	PairingSessionExchange(mAirPlayClientConnection->pairVerifySessionHomeKit,"",0, &outputPtr, &outputLen,&done);

	HTTPMessageSetBodyPtr( httpMessage, kMIMEType_Binary, outputPtr, outputLen );
	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl pair-verifyM1 Request **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	// send the request

	err = HTTPClientSendMessageSync( gHttpClient, httpMessage );
	require_noerr( err, exit );
	increaseSyncNumber();

	// Read the response header
	if(!IsHTTPStatusCode_Success( httpMessage->header.statusCode )){
		PairingSessionReset(mAirPlayClientConnection->pairVerifySessionHomeKit);
	}
	require_action( httpMessage->header.statusCode != 0, exit, err = kResponseErr );
	require_action( IsHTTPStatusCode_Success( httpMessage->header.statusCode ), exit, err = HTTPStatusToOSStatus( httpMessage->header.statusCode ) );

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl pair-verifyM1 Response **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	//解析HTTP Message
	uint8_t *  responseBodyPtr    = httpMessage->bodyPtr;
	size_t     responseBodyOffset = httpMessage->bodyOffset;
	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Response bodyOffset: %d \n", responseBodyOffset);
	PairingSessionExchange(mAirPlayClientConnection->pairVerifySessionHomeKit,responseBodyPtr,responseBodyOffset, &outputPtr, &outputLen,&done);

	if( !done )
	{
		cpcc_ulog( kLogLevelTrace, "********** CarPlayControl pair-verify step1 failed,then setup.\n");
		dispatch_async_f(inClient->httpClientQueue, SHARK_EVENT_PAIR_SETUP, _CarPlayControlClientEvent);
		goto exit;
	}

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl pair-verify step1 finish: %d \n", outputLen);
	if(gCacheBodyPtr)
	{
		CFReleaseNullSafe( gCacheBodyPtr );
	}
	gCacheBodyPtr = malloc( sizeof(uint8_t) * outputLen );
	gCacheBodyOffset = ( sizeof(uint8_t) * outputLen );
	memset( gCacheBodyPtr, 0,sizeof( uint8_t ) * outputLen );
	memcpy( gCacheBodyPtr, outputPtr,sizeof( uint8_t ) * outputLen );

	dispatch_async_f(inClient->httpClientQueue, SHARK_EVENT_PAIR_VERIFY1, _CarPlayControlClientEvent);

exit:
	if( err )	cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" failed    @ %N: %#m\n", inCommand, err );
	else		cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" completed @ %N\n", inCommand);

	ForgetMem( &hostNameWithInterfaceNdx );
	CFReleaseNullSafe( httpMessage );

	return( err );
}

//===========================================================================================================================
//	_CarPlayControlClientPairSetup3
//===========================================================================================================================

static OSStatus
	_CarPlayControlClientPairSetup3(
		CarPlayControlClientRef inClient, CarPlayBonjourServiceRef inService, const char *inCommand )
{
	HTTPStatus		    status;
	OSStatus			err;
	HTTPMessageRef		httpMessage = NULL;

	cpcc_ulog( kLogLevelNotice, "CarPlayControl pair-setup step3 \n" );

	// Build the request

	err = HTTPMessageCreate( &httpMessage );
	require_noerr( err, exit );

	char url[32];
	snprintf( url, sizeof(url), "/pair-setup", "" );
	err = HTTPHeader_InitRequest( &httpMessage->header, kHTTPMethodString_POST, url, kRTSPVersionString_1pt1 );
	require_noerr( err, exit );

	//CSeq
	char CSeq[32];
	snprintf( CSeq, sizeof(CSeq), "%d", m_SyncNumber );
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_CSeq, CSeq );
	require_noerr( err, exit );

	//User-Agent
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_UserAgent, kAirPlayUserAgentStr );
	require_noerr( err, exit );

	//Content-Type
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_ContentType, kMIMEType_Binary );
	require_noerr( err, exit );

	//"X-Apple-AbsoluteTime" : "701686240",
	err = HTTPHeader_AddField( &httpMessage->header, "X-Apple-AbsoluteTime", "701686240" );
	require_noerr( err, exit );

	//"X-Apple-Client-Name" : "clare的 iPhone",
	err = HTTPHeader_AddField( &httpMessage->header, "X-Apple-Client-Name", gOEMBrand );
	require_noerr( err, exit );

	//"X-Apple-HKP" : "0",
	err = HTTPHeader_AddField( &httpMessage->header, "X-Apple-HKP", "0" );
	require_noerr( err, exit );

	//Payload data
	uint8_t *				outputPtr	= NULL;
	size_t					outputLen	= 0;
	Boolean					done;


	//PairingSessionExchange(mAirPlayClientConnection->pairVerifySessionHomeKit,"",0, &outputPtr, &outputLen,&done);
	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl pair-setupM3 outputLen= %d \n", outputLen);
	HTTPMessageSetBodyPtr( httpMessage, kMIMEType_Binary, gCacheBodyPtr, gCacheBodyOffset );
	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl pair-setupM3 Request **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	// send the request

	err = HTTPClientSendMessageSync( gHttpClient, httpMessage );
	require_noerr( err, exit );
	increaseSyncNumber();

	// Read the response header
	require_action( httpMessage->header.statusCode != 0, exit, err = kResponseErr );
	require_action( IsHTTPStatusCode_Success( httpMessage->header.statusCode ), exit, err = HTTPStatusToOSStatus( httpMessage->header.statusCode ) );

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl pair-setupM3 Response **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );


	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl httpMessage->bodyOffset: %d \n", httpMessage->bodyOffset);

	PairingSessionExchange(mAirPlayClientConnection->pairSetupSessionHomeKit,httpMessage->bodyPtr,httpMessage->bodyOffset, &outputPtr, &outputLen,&done);
	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl pair-setup step3 finish : %d \n", outputLen);

	if(gCacheBodyPtr)
	{
		CFReleaseNullSafe( gCacheBodyPtr );
	}

	gCacheBodyPtr = malloc( sizeof(uint8_t) * outputLen );
	gCacheBodyOffset = ( sizeof(uint8_t) * outputLen );
	memset( gCacheBodyPtr, 0, ( sizeof(uint8_t) * outputLen ));
	memcpy( gCacheBodyPtr, outputPtr, ( sizeof(uint8_t) * outputLen ));


	dispatch_async_f(inClient->httpClientQueue, SHARK_EVENT_PAIR_SETUP3, _CarPlayControlClientEvent);

exit:
	if( err )	cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" failed    @ %N: %#m\n", inCommand, err );
	else		cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" completed @ %N\n", inCommand);

	CFReleaseNullSafe( httpMessage );
	return( err );
}

//===========================================================================================================================
//	_CarPlayControlClientPairSetup2
//===========================================================================================================================

static OSStatus
	_CarPlayControlClientPairSetup2(
		CarPlayControlClientRef inClient, CarPlayBonjourServiceRef inService, const char *inCommand )
{
	HTTPStatus		    status;
	OSStatus			err;
	HTTPMessageRef		httpMessage = NULL;

	cpcc_ulog( kLogLevelNotice, "CarPlayControl pair-setup step2 \n" );

	// Build the request

	err = HTTPMessageCreate( &httpMessage );
	require_noerr( err, exit );

	char url[32];
	snprintf( url, sizeof(url), "/pair-setup", "" );
	err = HTTPHeader_InitRequest( &httpMessage->header, kHTTPMethodString_POST, url, kRTSPVersionString_1pt1 );
	require_noerr( err, exit );

	//CSeq
	char CSeq[32];
	snprintf( CSeq, sizeof(CSeq), "%d", m_SyncNumber );
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_CSeq, CSeq );
	require_noerr( err, exit );

	//User-Agent
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_UserAgent, kAirPlayUserAgentStr );
	require_noerr( err, exit );

	//Content-Type
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_ContentType, kMIMEType_Binary );
	require_noerr( err, exit );

	//"X-Apple-AbsoluteTime" : "701686240",
	err = HTTPHeader_AddField( &httpMessage->header, "X-Apple-AbsoluteTime", "701686240" );
	require_noerr( err, exit );

	//"X-Apple-Client-Name" : "clare的 iPhone",
	err = HTTPHeader_AddField( &httpMessage->header, "X-Apple-Client-Name", gOEMBrand );
	require_noerr( err, exit );

	//"X-Apple-HKP" : "0",
	err = HTTPHeader_AddField( &httpMessage->header, "X-Apple-HKP", "0" );
	require_noerr( err, exit );

	//Payload data
	uint8_t *				outputPtr	= NULL;
	size_t					outputLen	= 0;
	Boolean					done;


	//PairingSessionExchange(mAirPlayClientConnection->pairVerifySessionHomeKit,"",0, &outputPtr, &outputLen,&done);
	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl pair-setupM2 outputLen= %d \n", outputLen);
	HTTPMessageSetBodyPtr( httpMessage, kMIMEType_Binary, gCacheBodyPtr, gCacheBodyOffset );
	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl pair-setupM2 Request **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	// send the request

	err = HTTPClientSendMessageSync( gHttpClient, httpMessage );
	require_noerr( err, exit );
	increaseSyncNumber();

	// Read the response header
	if(!IsHTTPStatusCode_Success( httpMessage->header.statusCode )){
		PairingSessionReset(mAirPlayClientConnection->pairSetupSessionHomeKit);
	}
	require_action( httpMessage->header.statusCode != 0, exit, err = kResponseErr );
	require_action( IsHTTPStatusCode_Success( httpMessage->header.statusCode ), exit, err = HTTPStatusToOSStatus( httpMessage->header.statusCode ) );

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl pair-setupM2 Response **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );


	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl httpMessage->bodyOffset: %d \n", httpMessage->bodyOffset);

	PairingSessionExchange(mAirPlayClientConnection->pairSetupSessionHomeKit,httpMessage->bodyPtr,httpMessage->bodyOffset, &outputPtr, &outputLen,&done);
	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl pair-setup step2 finish : %d \n", outputLen);

	if( gCacheBodyPtr )
	{
		CFReleaseNullSafe( gCacheBodyPtr );
	}

	gCacheBodyPtr = malloc( sizeof(uint8_t) * outputLen );
	gCacheBodyOffset = sizeof(uint8_t) * outputLen;
	memset( gCacheBodyPtr, 0, sizeof(uint8_t) * outputLen );
	memcpy( gCacheBodyPtr, outputPtr, sizeof(uint8_t) * outputLen );

	dispatch_async_f(inClient->httpClientQueue, SHARK_EVENT_PAIR_SETUP2, _CarPlayControlClientEvent);

exit:
	if( err )	cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" failed    @ %N: %#m\n", inCommand, err );
	else		cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" completed @ %N\n", inCommand);

	CFReleaseNullSafe( httpMessage );

	return( err );
}

static OSStatus _CreateHTTPClientRef(char * hostNameWithInterfaceNdx,uint16_t port,dispatch_queue_t httpQueue)
{

	OSStatus			err;
	HTTPClientFlags		httpFlags;
	HTTPClientRef		httpClient = NULL;

	err = HTTPClientCreate( &httpClient );
	require_noerr( err, exit );

	HTTPClientSetDispatchQueue( httpClient, httpQueue );
	HTTPClientSetTimeout( httpClient, kCarPlayControlClient_ConnectionTimeoutSeconds );

	HTTPClientSetLogging( httpClient, &log_category_from_name( CarPlayControlClient ) );
	HTTPClientSetConnectionLogging( httpClient, &log_category_from_name( CarPlayControlClient ) );

	err = HTTPClientSetDestination( httpClient, hostNameWithInterfaceNdx, port );
	require_noerr( err, exit );

	httpFlags = kHTTPClientFlag_Reachability;
	HTTPClientSetFlags( httpClient, httpFlags, httpFlags );

	if( gHttpClient ){
		HTTPClientForget( &gHttpClient );
	}
	gHttpClient = httpClient;

exit:
	return err;
}

//===========================================================================================================================
//	_CarPlayControlClientPairSetup  pair-setup: M1-->M3-->M5
//===========================================================================================================================

static OSStatus
	_CarPlayControlClientPairSetup(
		CarPlayControlClientRef inClient, CarPlayBonjourServiceRef inService, const char *inCommand )
{
	HTTPStatus		    status;
	OSStatus			err;
	const char *		hostName = NULL;
	char *				hostNameWithInterfaceNdx = NULL;
	uint16_t			port = 0;
	uint32_t			interfaceNdx = 0;
	HTTPMessageRef		httpMessage = NULL;

	// Get the service address
	cpcc_ulog( kLogLevelNotice, "CarPlayControl pair-setup step1 \n" );
	if( inService )
	{
		err = CarPlayBonjourServiceGetAddress( inService, &hostName, &port, &interfaceNdx );
		require_noerr( err, exit );
		if( strlen ( gBonjourIPAddress ) > 0 )
		{
			asprintf( &hostNameWithInterfaceNdx, "%s%s",gBonjourIPAddress,"%usb0" );
		}else{
			asprintf( &hostNameWithInterfaceNdx, "%s%%%u", hostName, (unsigned)interfaceNdx );
		}
	}
	else {
		asprintf( &hostNameWithInterfaceNdx, "%s%s",gBonjourIPAddress,"%usb0" );
		port = gBonjourPort;
	}


	// Connect to the controller

//	cpcc_ulog( kLogLevelNotice, "CarPlayControl connecting to %s on port %d\n", hostNameWithInterfaceNdx, (int) port );
	err = _CreateHTTPClientRef( hostNameWithInterfaceNdx, port, inClient->httpQueue);
	// Build the request

	err = HTTPMessageCreate( &httpMessage );
	require_noerr( err, exit );

	char url[32];
	snprintf( url, sizeof(url), "/pair-setup", "" );
	err = HTTPHeader_InitRequest( &httpMessage->header, kHTTPMethodString_POST, url, kRTSPVersionString_1pt1 );
	require_noerr( err, exit );

	//CSeq
	char CSeq[32];
	snprintf( CSeq, sizeof(CSeq), "%d", m_SyncNumber );
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_CSeq, CSeq );
	require_noerr( err, exit );

	//User-Agent
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_UserAgent, kAirPlayUserAgentStr );
	require_noerr( err, exit );

	//Content-Type
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_ContentType, kMIMEType_Binary );
	require_noerr( err, exit );

	//"X-Apple-AbsoluteTime" : "701686240",
	err = HTTPHeader_AddField( &httpMessage->header, "X-Apple-AbsoluteTime", "701686240" );
	require_noerr( err, exit );

	//"X-Apple-Client-Name" : "clare的 iPhone",
	err = HTTPHeader_AddField( &httpMessage->header, "X-Apple-Client-Name", gOEMBrand );
	require_noerr( err, exit );

	//"X-Apple-HKP" : "2",
	err = HTTPHeader_AddField( &httpMessage->header, "X-Apple-HKP", "0" );
	require_noerr( err, exit );

	//Connection: keep-alive
	err = HTTPHeader_AddField( &httpMessage->header, "Connection", "keep-alive" );
	require_noerr( err, exit );

	//Payload data
	//Generate the public key to accessory
	err = PairingSessionCreate( &mAirPlayClientConnection->pairSetupSessionHomeKit, NULL, kPairingSessionType_SetupClient );
	require_noerr_action( err, exit, status = kHTTPStatus_InternalServerError );

	PairingSessionReset(mAirPlayClientConnection->pairSetupSessionHomeKit);

	PairingSessionSetKeychainInfo_AirPlay( mAirPlayClientConnection->pairSetupSessionHomeKit );
	PairingSessionSetLogging( mAirPlayClientConnection->pairSetupSessionHomeKit, cpcc_http_ucat() );

	char	deviceId[ 40 ];
	// __system_property_get("sys.xq.product.deviceid", deviceId);
	err = PairingSessionSetIdentifier( mAirPlayClientConnection->pairSetupSessionHomeKit, deviceId, kSizeCString );
	require_noerr_action( err, exit, status = kHTTPStatus_InternalServerError );

    err = PairingSessionSetSetupCode( mAirPlayClientConnection->pairSetupSessionHomeKit, "3939", kSizeCString);
    require_noerr_action(err, exit, status = kHTTPStatus_InternalServerError);

	uint8_t *				outputPtr	= NULL;
	size_t					outputLen	= 0;
	Boolean					done;
	PairingSessionExchange(mAirPlayClientConnection->pairSetupSessionHomeKit,"",0, &outputPtr, &outputLen,&done);
	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl pair-setupM1 outputLen= %d \n", outputLen);
	HTTPMessageSetBodyPtr( httpMessage, kMIMEType_Binary, outputPtr, outputLen );
	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl pair-setupM1 0950 Request **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	// send the request

	err = HTTPClientSendMessageSync( gHttpClient, httpMessage );
	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl pair-setupM1 err statusCode = %d \n" , httpMessage->header.statusCode);
	if( httpMessage->header.statusCode == kHTTPStatus_NotFound || httpMessage->header.statusCode == kHTTPStatus_MethodNotValidInThisState )
	{
		//确定要走aes加密方式
		gHomeKitEnable = 0;
		if(mAirPlayClientConnection->pairVerifySessionHomeKit){
			cpcc_ulog( kLogLevelTrace, "********** CarPlayControl pairVerifySessionHomeKit is useful \n" );
		}else{
			cpcc_ulog( kLogLevelTrace, "********** CarPlayControl pairVerifySessionHomeKit is unuseful \n" );
		}
		uint64_t nanos=(int64_t)(1 * NSEC_PER_SEC);
		dispatch_after_f(dispatch_time( DISPATCH_TIME_NOW, nanos ), inClient->httpClientQueue,
				SHARK_EVENT_SESSION_HOMEKIT_DISABLE, _CarPlayControlClientEvent);
	}
	require_noerr( err, exit );
	increaseSyncNumber();

	// Read the response header


	if(!IsHTTPStatusCode_Success( httpMessage->header.statusCode )){
		PairingSessionReset(mAirPlayClientConnection->pairSetupSessionHomeKit);
	}
	require_action( httpMessage->header.statusCode != 0, exit, err = kResponseErr );
	require_action( IsHTTPStatusCode_Success( httpMessage->header.statusCode ), exit, err = HTTPStatusToOSStatus( httpMessage->header.statusCode ) );

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl pair-setupM1 Response **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );


	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl httpMessage->bodyOffset: %d \n", httpMessage->bodyOffset);

	PairingSessionExchange(mAirPlayClientConnection->pairSetupSessionHomeKit,httpMessage->bodyPtr,httpMessage->bodyOffset, &outputPtr, &outputLen,&done);
	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl pair-setup step1 finish : %d \n", outputLen);

	gCacheBodyPtr = malloc( sizeof(uint8_t) * outputLen );
	gCacheBodyOffset = sizeof(uint8_t) * outputLen;
	memset( gCacheBodyPtr, 0, sizeof(uint8_t)*outputLen );
	memcpy( gCacheBodyPtr, outputPtr, sizeof(uint8_t)*outputLen );


	dispatch_async_f(inClient->httpClientQueue, SHARK_EVENT_PAIR_SETUP1, _CarPlayControlClientEvent);

exit:
	if( err )	cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" failed    @ %N: %#m\n", inCommand, err );
	else		cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" completed @ %N\n", inCommand);

	ForgetMem( &hostNameWithInterfaceNdx );
	CFReleaseNullSafe( httpMessage );

	return( err );
}

//===========================================================================================================================
//	_CarPlayControlClientRtspRecord
//===========================================================================================================================

static OSStatus
	_CarPlayControlClientRtspRecord(
		CarPlayControlClientRef inClient, CarPlayBonjourServiceRef inService, const char *inCommand )
{
	OSStatus			err;
	char *				rtspHostName = NULL;
	HTTPMessageRef		httpMessage = NULL;

	// Build the request

	err = HTTPMessageCreate( &httpMessage );
	require_noerr( err, exit );

	char	url[ 100 ];
	char	ipv6[ 100 ];
	memset(url,0,100);
	memcpy(url, mAirPlayClientConnection->peerUrl,100);
	int index=indexOf(url, 0, 100, "%", 0, 1, 0);
	//%usb0
	if(index>0)
	{
		strlcpy(ipv6,url,(index+1));
//		cpcc_ulog( kLogLevelTrace, "TinkerIPV6 %s\n", ipv6 );
	}else{
		strlcpy(ipv6,url,strlen(url));
	}

	asprintf( &rtspHostName, "%s%s%s%llu", "rtsp://", ipv6, "/",gMeSessionUUID);
//	cpcc_ulog( kLogLevelTrace, "rtspHostName %s\n", rtspHostName );
	err = HTTPHeader_InitRequest( &httpMessage->header, kHTTPMethodString_RECORD, rtspHostName, kRTSPVersionString_1pt1 );
	require_noerr( err, exit );

	//CSeq
	char CSeq[32];
	snprintf( CSeq, sizeof(CSeq), "%d", m_SyncNumber );
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_CSeq, CSeq );
	require_noerr( err, exit );

	//User-Agent
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_UserAgent, kAirPlayUserAgentStr );
	require_noerr( err, exit );

	//X-Apple-ProtocolVersion: 1
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_ProtocolVersion, "1" );
	require_noerr( err, exit );

	//Content-Length
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_ContentLength, "0" );
	require_noerr( err, exit );

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Request **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	// send the request

	err = HTTPClientSendMessageSync( gHttpClient, httpMessage );
	require_noerr( err, exit );
	increaseSyncNumber();

	// Read the response header

	require_action( httpMessage->header.statusCode != 0, exit, err = kResponseErr );
	require_action( IsHTTPStatusCode_Success( httpMessage->header.statusCode ), exit, err = HTTPStatusToOSStatus( httpMessage->header.statusCode ) );

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Response **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	_requestProcessRecordShark((mAirPlayClientConnection->session));
	dispatch_async_f(inClient->httpClientQueue, SHARK_EVENT_SESSION_RECORD, _CarPlayControlClientEvent);

exit:
	if( err )	cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" failed    @ %N: %#m\n", inCommand, err );
	else		cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" completed @ %N\n", inCommand);

	CFReleaseNullSafe( httpMessage );

	return( err );
}

//===========================================================================================================================
//	_CarPlayControlClientGetInfo
//===========================================================================================================================

static OSStatus
	_CarPlayControlClientGetInfo(
		CarPlayControlClientRef inClient, CarPlayBonjourServiceRef inService, const char *inCommand )
{
	OSStatus			err;
	HTTPMessageRef		httpMessage = NULL;

	// Connect to the controller

//	cpcc_ulog( kLogLevelNotice, "CarPlayControl connecting to %s on port %d\n", hostNameWithInterfaceNdx, (int) port );

	// Build the request

	err = HTTPMessageCreate( &httpMessage );
	require_noerr( err, exit );

	char url[32];
	snprintf( url, sizeof(url), "/info", "" );
	err = HTTPHeader_InitRequest( &httpMessage->header, kHTTPMethodString_GET, url, kRTSPVersionString_1pt1 );
	require_noerr( err, exit );

	//CSeq
	char CSeq[32];
	snprintf( CSeq, sizeof(CSeq), "%d", m_SyncNumber );
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_CSeq, CSeq );
	require_noerr( err, exit );

	//User-Agent
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_UserAgent, kAirPlayUserAgentStr );
	require_noerr( err, exit );

	//X-Apple-ProtocolVersion: 1
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_ProtocolVersion, "1" );
	require_noerr( err, exit );

	//Content-Length
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_ContentLength, "0" );
	require_noerr( err, exit );

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Request **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	// send the request

	err = HTTPClientSendMessageSync( gHttpClient, httpMessage );
	require_noerr( err, exit );
	increaseSyncNumber();

	// Read the response header

	require_action( httpMessage->header.statusCode != 0, exit, err = kResponseErr );
	require_action( IsHTTPStatusCode_Success( httpMessage->header.statusCode ), exit, err = HTTPStatusToOSStatus( httpMessage->header.statusCode ) );

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Response **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	CFDictionaryRef responseDict = (CFDictionaryRef)CFBinaryPlistV0CreateWithData(httpMessage->bodyPtr, httpMessage->bodyOffset, &err);
	require_noerr( err, exit );
//	cpcc_ulog( kLogLevelTrace, "/info responseDict = %@\n", responseDict );

	CFDictionaryRef			infoDict =NULL;

	if( !infoDict )
	{
		infoDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
	}
	AirPlayReceiverSessionControlEViLink((mAirPlayClientConnection->session), kCFObjectFlagDirect,  CFSTR( kAirPlayCommand_ModesChangedInit ), NULL, responseDict, &infoDict);

	dispatch_async_f(inClient->httpClientQueue, SHARK_EVENT_SESSION_GET_INFO, _CarPlayControlClientEvent);

exit:
	if( err )	cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" failed    @ %N: %#m\n", inCommand, err );
	else		cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" completed @ %N\n", inCommand);

	CFReleaseNullSafe( httpMessage );
	if( infoDict ) CFReleaseNullSafe( infoDict );

	return( err );
}

//===========================================================================================================================
//	_CarPlayControlClientAuthSetup
//===========================================================================================================================

static OSStatus
	_CarPlayControlClientAuthSetup(
		CarPlayControlClientRef inClient, CarPlayBonjourServiceRef inService, const char *inCommand )
{
	OSStatus			err;
	const char *		hostName = NULL;
	char *				hostNameWithInterfaceNdx = NULL;
	uint16_t			port = 0;
	uint32_t			interfaceNdx = 0;
	HTTPMessageRef		httpMessage = NULL;
	HTTPClientFlags		httpFlags;

	// Get the service address
	if( inService )
	{
		err = CarPlayBonjourServiceGetAddress( inService, &hostName, &port, &interfaceNdx );
		require_noerr( err, exit );
		if( strlen ( gBonjourIPAddress ) > 0 )
		{
			asprintf( &hostNameWithInterfaceNdx, "%s%s",gBonjourIPAddress,"%usb0" );
		}else{
			asprintf( &hostNameWithInterfaceNdx, "%s%%%u", hostName, (unsigned)interfaceNdx );
		}
	}
	else {
		asprintf( &hostNameWithInterfaceNdx, "%s%s",gBonjourIPAddress,"%usb0" );
		port = gBonjourPort;
	}

	// Connect to the controller


	if(!gHttpClient)
	{
		err = _CreateHTTPClientRef(hostNameWithInterfaceNdx, port, inClient->httpQueue);
	}
//	cpcc_ulog( kLogLevelNotice, "CarPlayControl connecting to %s on port %d\n", hostNameWithInterfaceNdx, (int) port );

	// Build the request

	err = HTTPMessageCreate( &httpMessage );
	require_noerr( err, exit );

	char url[32];
	snprintf( url, sizeof(url), "/auth-setup", "" );
	err = HTTPHeader_InitRequest( &httpMessage->header, kHTTPMethodString_POST, url, kRTSPVersionString_1pt1 );
	require_noerr( err, exit );

	//CSeq
	char CSeq[32];
	snprintf( CSeq, sizeof(CSeq), "%d", m_SyncNumber );
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_CSeq, CSeq );
	require_noerr( err, exit );

	//User-Agent
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_UserAgent, kAirPlayUserAgentStr );
	require_noerr( err, exit );

	//X-Apple-ProtocolVersion: 1
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_ProtocolVersion, "1" );
	require_noerr( err, exit );

	//Content-Length
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_ContentLength, "33" );
	require_noerr( err, exit );

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Request **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	//payload
	uint8_t				ourSK[ 32 ];
	uint8_t				ourPK[ 32 ];
	MFiSAP_GenerateKeyPair(NULL, ourPK, ourSK);

	memcpy(mAirPlayClientConnection->ourPK, ourPK, 32);
	memcpy(mAirPlayClientConnection->ourSK, ourSK, 32);



	uint8_t* ptr = malloc(sizeof(uint8_t) * 33);
	memset(ptr, 0, sizeof(uint8_t) * 33);
	ptr[0] = 0x01;
	memcpy(ptr+1,ourPK,sizeof(uint8_t) * 32);

	HTTPMessageSetBodyPtr( httpMessage, kMIMEType_Binary, ptr, sizeof(uint8_t) * 33);
	// send the request

	err = HTTPClientSendMessageSync( gHttpClient, httpMessage );
	require_noerr( err, exit );
	increaseSyncNumber();
	// __system_property_set("sys.shark.carplay.net.ok", "1");

	// Read the response header
	require_action( httpMessage->header.statusCode != 0, exit, err = kResponseErr );
	require_action( IsHTTPStatusCode_Success( httpMessage->header.statusCode ), exit, err = HTTPStatusToOSStatus( httpMessage->header.statusCode ) );

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Response **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	//Read the peer public key
	if( httpMessage->bodyOffset > 0 && gHomeKitEnable == 0)
	{
		cpcc_ulog( kLogLevelTrace, "public_httpMessage->bodyOffset %d\n", httpMessage->bodyOffset );

		uint8_t* respBodyPtr =(uint8_t*) malloc( httpMessage->bodyOffset );
		memset(respBodyPtr, 0, httpMessage->bodyOffset);
		memcpy(respBodyPtr, httpMessage->bodyPtr, httpMessage->bodyOffset);

		int pointer = 0;
		uint8_t peerPK[ 32 ] = { 0 };
		memcpy(peerPK, respBodyPtr, 32);
		pointer += 32;

		//这里生成aesKey aesIV
		MFiSAP_GenerateAesKeyPair(mAirPlayClientConnection->MFiSAP, ourSK, peerPK, mAirPlayClientConnection->aesKey, mAirPlayClientConnection->aesIV);

		uint32_t certificateLen = 0;
		uint8_t certLen [ 4 ] = { 0 };
		memcpy(certLen, respBodyPtr+pointer, 4);
		pointer += 4;

		certificateLen = ReadBig32( certLen );
//		cpcc_ulog( kLogLevelTrace, "public_httpMessage->certificateLen %d\n", certificateLen );
		uint8_t* certificate =(uint8_t*) malloc( certificateLen );
		memcpy(certificate, respBodyPtr+pointer, certificateLen);
		pointer += certificateLen;


		uint32_t signatureLen = 0;
		uint8_t signLen [ 4 ] = { 0 };
		memcpy(signLen, respBodyPtr+pointer, 4);
		pointer += 4;

		signatureLen = ReadBig32( signLen );
//		cpcc_ulog( kLogLevelTrace, "public_httpMessage->signatureLen %d\n", signatureLen );
		uint8_t* signaturePtr =(uint8_t*) malloc( signatureLen );
		memcpy(signaturePtr, respBodyPtr+pointer, signatureLen);

		// Decrypt the signature with the AES key and IV.
		MFiSAP_Init(mAirPlayClientConnection->MFiSAP, mAirPlayClientConnection->aesKey, mAirPlayClientConnection->aesIV );
		MFiSAP_Decrypt(mAirPlayClientConnection->MFiSAP, signaturePtr, signatureLen, signaturePtr);

		free(signaturePtr);
		free(certificate);
		free(respBodyPtr);

	}
	sockaddr_ip	sip;
	size_t	len;
	// connect to the sender event socket
	err = HTTPClientGetPeerAddress( gHttpClient, &sip, sizeof( sip ), &len );
	require_noerr( err, exit );

	//Tinker patch >>>
	memset( mAirPlayClientConnection->peerUrl, 0, 100);
	const sockaddr_ip * const		peerIP = (const sockaddr_ip *) &sip;
	if( ( peerIP->sa.sa_family == AF_INET6 ))
	{
		cpcc_ulog( kLogLevelTrace, "TinkerResolved AF_INET6 \n");
		char			peerUrl[ 100 ];
		memset( peerUrl, 0, 100);
		SockAddrToString(peerIP, kSockAddrStringFlagsNoPort, peerUrl );
		cpcc_ulog( kLogLevelTrace, "TinkerResolved address: %s \n",peerUrl);
		memcpy( mAirPlayClientConnection->peerUrl, peerUrl, 100);
	}
	else if( ( peerIP->sa.sa_family == AF_INET ))
	{
		cpcc_ulog( kLogLevelTrace, "TinkerResolved AF_INET \n");
		char			peerUrl[ 100 ];
		memset( peerUrl, 0, 100);
		SockAddrToString(peerIP, kSockAddrStringFlagsNoPort, peerUrl );
		cpcc_ulog( kLogLevelTrace, "TinkerResolved address: %s \n",peerUrl);
		memcpy( mAirPlayClientConnection->peerUrl, peerUrl, 100);
	}
	SockAddrCopy(&sip, &mAirPlayClientConnection->peerAddr);

	//Tinker patch <<<

	dispatch_async_f(inClient->httpClientQueue, SHARK_EVENT_PAIR_AUTH_SETUP, _CarPlayControlClientEvent);

exit:
	if( err )	cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" failed    @ %N: %#m\n", inCommand, err );
	else		cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" completed @ %N\n", inCommand);


	ForgetMem( &hostNameWithInterfaceNdx );
	if (ptr) {
		CFReleaseNullSafe( ptr );
	}
	CFReleaseNullSafe( httpMessage );
	return( err );
}

//===========================================================================================================================
//	_CarPlayControlClientFeedback
//===========================================================================================================================

static OSStatus
	_CarPlayControlClientFeedback(
		CarPlayControlClientRef inClient, CarPlayBonjourServiceRef inService, const char *inCommand )
{
	OSStatus			err;
	HTTPMessageRef		httpMessage = NULL;

	// Build the request

	err = HTTPMessageCreate( &httpMessage );
	require_noerr( err, exit );

	char url[32];
	snprintf( url, sizeof(url), "/feedback", "" );
	err = HTTPHeader_InitRequest( &httpMessage->header, kHTTPMethodString_POST, url, kRTSPVersionString_1pt1 );
	require_noerr( err, exit );

	//CSeq
	char CSeq[32];
	snprintf( CSeq, sizeof(CSeq), "%d", m_SyncNumber );
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_CSeq, CSeq );
	require_noerr( err, exit );

	//User-Agent
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_UserAgent, kAirPlayUserAgentStr );
	require_noerr( err, exit );


//	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Request **********\n" );
//	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	// send the request

	err = HTTPClientSendMessageSync( gHttpClient, httpMessage );
	require_noerr( err, exit );
	increaseSyncNumber();

	// Read the response header

	require_action( httpMessage->header.statusCode != 0, exit, err = kResponseErr );
	require_action( IsHTTPStatusCode_Success( httpMessage->header.statusCode ), exit, err = HTTPStatusToOSStatus( httpMessage->header.statusCode ) );

//	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Response **********\n" );
//	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

//	dispatch_async_f(inClient->httpClientQueue, SHARK_EVENT_SESSION_FEEDBACK, _CarPlayControlClientEvent);
	uint64_t nanos=(int64_t)(2 * NSEC_PER_SEC);
	dispatch_after_f(dispatch_time( DISPATCH_TIME_NOW, nanos ), inClient->httpClientQueue,
			SHARK_EVENT_SESSION_FEEDBACK, _CarPlayControlClientEvent);

exit:
	if( err )
	{
		cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" failed    @ %N: %#m\n", inCommand, err );
//		usleep(1000*1500);
//		system("reboot");
//		exit(0);
		_CarPlayControlClientEnsureStopped(gCarPlayClient);
	}
//	else		cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" completed @ %N\n", inCommand);


	CFReleaseNullSafe( httpMessage );
	return( err );
}

//===========================================================================================================================
//	_CarPlayControlClientPostCommand  modesChanged
//===========================================================================================================================

static OSStatus
	_CarPlayControlClientPostCommandModesChanged(
		CarPlayControlClientRef inClient, CarPlayBonjourServiceRef inService, const char *inCommand )
{
	OSStatus			err;
	HTTPMessageRef		httpMessage = NULL;

	// Build the request

	err = HTTPMessageCreate( &httpMessage );
	require_noerr( err, exit );

	char url[32];
	snprintf( url, sizeof(url), "/command", "" );
	err = HTTPHeader_InitRequest( &httpMessage->header, kHTTPMethodString_POST, url, kRTSPVersionString_1pt1 );
	require_noerr( err, exit );

	//CSeq
	char CSeq[32];
	snprintf( CSeq, sizeof(CSeq), "%d", m_SyncNumber );
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_CSeq, CSeq );
	require_noerr( err, exit );

	//User-Agent
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_UserAgent, kAirPlayUserAgentStr );
	require_noerr( err, exit );

	//X-Apple-ProtocolVersion: 1
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_ProtocolVersion, "1" );
	require_noerr( err, exit );

	//Payload data

	CFDictionaryRef			requestDict =NULL;
	CFDictionaryRef			paramsDict =NULL;
	if( !requestDict )
	{
		requestDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
	}
	if( !paramsDict )
	{
		paramsDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
	}

    //appStates
	CFMutableArrayRef appStates=CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
	require_action( appStates, exit, err = kNoMemoryErr );

	AirPlayModeState * modeState = AirPlayReceiverSessionControlGetAppState((mAirPlayClientConnection->session));

	cpcc_ulog( kLogLevelTrace, "[rtsp] mode_changed \n" ,requestDict);
	cpcc_ulog( kLogLevelTrace, "[rtsp] ######################################### \n" );
	cpcc_ulog( kLogLevelTrace, "[rtsp] main audio: %s \n" ,AirPlayEntityToString( modeState->mainAudio ));
	cpcc_ulog( kLogLevelTrace, "[rtsp] permAudio: %s \n" ,AirPlayEntityToString( modeState->permMainAudio ));
	cpcc_ulog( kLogLevelTrace, "[rtsp] screen: %s \n" ,AirPlayEntityToString( modeState->screen ));
	cpcc_ulog( kLogLevelTrace, "[rtsp] permScreen: %s \n" ,AirPlayEntityToString( modeState->permScreen ));
	cpcc_ulog( kLogLevelTrace, "[rtsp] phone call: %s \n" ,AirPlayEntityToString( modeState->phoneCall ));
	cpcc_ulog( kLogLevelTrace, "[rtsp] speech: %s (%s)\n" ,AirPlayEntityToString( modeState->speech.entity ),AirPlaySpeechModeToString( modeState->speech.mode ));
	cpcc_ulog( kLogLevelTrace, "[rtsp] turn by turn: %s \n" ,AirPlayEntityToString( modeState->turnByTurn ));
	cpcc_ulog( kLogLevelTrace, "[rtsp] ######################################### \n");

	//1.Speech entity
	CFDictionaryRef  speechEntity = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
            &kCFTypeDictionaryValueCallBacks);
	require_action(speechEntity, exit, err = kNoMemoryErr);
	CFDictionarySetInt64( speechEntity, CFSTR( kAirPlayKey_AppStateID ), kAirPlayAppStateID_Speech );

	CFDictionarySetInt64( speechEntity, CFSTR( kAirPlayKey_Entity ), modeState->speech.entity );
//	CFDictionarySetInt64( speechEntity, CFSTR( kAirPlayKey_Entity ), kAirPlayEntity_NotApplicable );
//	CFDictionarySetInt64( speechEntity, CFSTR( kAirPlayKey_SpeechMode ), kAirPlaySpeechMode_None );
	CFDictionarySetInt64( speechEntity, CFSTR( kAirPlayKey_SpeechMode ), modeState->speech.mode );
	CFArrayAppendValue( appStates, speechEntity );

	//2.PhoneCall entity
	CFDictionaryRef  phoneCallEntity = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
            &kCFTypeDictionaryValueCallBacks);
	require_action(phoneCallEntity, exit, err = kNoMemoryErr);
	CFDictionarySetInt64( phoneCallEntity, CFSTR( kAirPlayKey_AppStateID ), kAirPlayAppStateID_PhoneCall );
//	CFDictionarySetInt64( phoneCallEntity, CFSTR( kAirPlayKey_Entity ), kAirPlayEntity_NotApplicable );
	CFDictionarySetInt64( phoneCallEntity, CFSTR( kAirPlayKey_Entity ), modeState->phoneCall );
	CFArrayAppendValue( appStates, phoneCallEntity );

	//3.TurnByTurn entity
	CFDictionaryRef  turnByTurnEntity = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
            &kCFTypeDictionaryValueCallBacks);
	require_action(turnByTurnEntity, exit, err = kNoMemoryErr);
	CFDictionarySetInt64( turnByTurnEntity, CFSTR( kAirPlayKey_AppStateID ), kAirPlayAppStateID_TurnByTurn );
//	CFDictionarySetInt64( turnByTurnEntity, CFSTR( kAirPlayKey_Entity ), kAirPlayEntity_NotApplicable );
	CFDictionarySetInt64( turnByTurnEntity, CFSTR( kAirPlayKey_Entity ), modeState->turnByTurn );
	CFArrayAppendValue( appStates, turnByTurnEntity );

    //resources
	CFMutableArrayRef resources=CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
	require_action( appStates, exit, err = kNoMemoryErr );


	//1.resources-MainScreen
	CFDictionaryRef  resMainScreenEntity = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
            &kCFTypeDictionaryValueCallBacks);
	require_action(resMainScreenEntity, exit, err = kNoMemoryErr);
	CFDictionarySetInt64( resMainScreenEntity, CFSTR( kAirPlayKey_ResourceID ), kAirPlayResourceID_MainScreen );
//	CFDictionarySetInt64( resMainScreenEntity, CFSTR( kAirPlayKey_Entity ), kAirPlayEntity_Accessory );
	CFDictionarySetInt64( resMainScreenEntity, CFSTR( kAirPlayKey_Entity ), modeState->screen );
	CFDictionarySetInt64( resMainScreenEntity, CFSTR( kAirPlayKey_PermanentEntity ), modeState->permScreen );
	CFArrayAppendValue( resources, resMainScreenEntity );

	//2.resources-MainAudio
	CFDictionaryRef  resMainAudioEntity = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
            &kCFTypeDictionaryValueCallBacks);
	require_action(resMainAudioEntity, exit, err = kNoMemoryErr);
	CFDictionarySetInt64( resMainAudioEntity, CFSTR( kAirPlayKey_ResourceID ), kAirPlayResourceID_MainAudio );
//	CFDictionarySetInt64( resMainAudioEntity, CFSTR( kAirPlayKey_Entity ), kAirPlayEntity_Accessory );
	CFDictionarySetInt64( resMainAudioEntity, CFSTR( kAirPlayKey_Entity ), modeState->mainAudio );
	CFDictionarySetInt64( resMainAudioEntity, CFSTR( kAirPlayKey_PermanentEntity ), modeState->permMainAudio );
	CFArrayAppendValue( resources, resMainAudioEntity );



	CFDictionarySetValue( paramsDict, CFSTR(kAirPlayKey_AppStates),appStates);
	CFDictionarySetValue( paramsDict, CFSTR(kAirPlayKey_Resources),resources);
	CFDictionarySetValue( requestDict, CFSTR( kAirPlayKey_Params ), paramsDict );
	CFDictionarySetValue( requestDict, CFSTR( kAirPlayKey_Type ), CFSTR( kAirPlayCommand_ModesChanged ) );

	//[Dictionary] Controller send command
	const uint8_t*      ptr;
	size_t              len;
    if (requestDict) {
    	cpcc_ulog( kLogLevelTrace, "sendCommand modesChanged requestDict = %@ \n" ,requestDict);
        ptr = CFBinaryPlistV0Create(requestDict, &len, NULL);
        err = HTTPMessageSetBodyPtr(httpMessage, kMIMEType_AppleBinaryPlist, ptr, len);
    }

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl modesChanged Request **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	// send the request

	err = HTTPClientSendMessageSync( gHttpClient, httpMessage );
	require_noerr( err, exit );
	increaseSyncNumber();

	// Read the response header

	require_action( httpMessage->header.statusCode != 0, exit, err = kResponseErr );
	require_action( IsHTTPStatusCode_Success( httpMessage->header.statusCode ), exit, err = HTTPStatusToOSStatus( httpMessage->header.statusCode ) );

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl modesChanged Response **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );


	if(strcmp(kAPSCarPlayControlCommandStr_SessionCommandModesChangedAudio,inCommand)==0){
		int targetChannel = modeState->targetPlayChannel;
		if( targetChannel != AUDIO_CHANNEL_STOP ){
			if( targetChannel == AUDIO_CHANNEL_NAVIGATION ){
				//导航声音
				dispatch_async_f(inClient->httpClientQueue, SHARK_EVENT_SESSION_MODES_DUCK_AUDIO, _CarPlayControlClientEvent);
			}else{
				dispatch_async_f(inClient->httpClientQueue, SHARK_EVENT_SESSION_POST_AUDIO_FOCUS_CHANGED, _CarPlayControlClientEvent);
			}
		}

		dispatch_async_f(inClient->httpClientQueue, targetChannel, _CarPlayControlClientAudioFocusGain);

	}
	else if(strcmp(kAPSCarPlayControlCommandStr_SessionCommandModesChangedTearDown,inCommand)==0){
		int targetChannel = modeState->targetStopChannel;
		int lastChannel = modeState->lastChannel;
		if( lastChannel != AUDIO_CHANNEL_STOP ){
			if( lastChannel == AUDIO_CHANNEL_NAVIGATION ){
				//导航声音
				dispatch_async_f(inClient->httpClientQueue, SHARK_EVENT_SESSION_MODES_UNDUCK_AUDIO, _CarPlayControlClientEvent);
			}
		}
		dispatch_async_f(inClient->httpClientQueue, targetChannel, _CarPlayControlClientAudioFocusLost);
	}
	else if(strcmp(kAPSCarPlayControlCommandStr_SessionCommandInteractive,inCommand)==0){
		cpcc_ulog( kLogLevelTrace, "********** CarPlayControl don't dispatch **********\n" );
	}else if(strcmp(kAPSCarPlayControlCommandStr_SessionCommand,inCommand)==0){
		cpcc_ulog( kLogLevelTrace, "********** CarPlayControl send dispatch **********\n" );
		dispatch_async_f(inClient->httpClientQueue, SHARK_EVENT_SESSION_POST_COMMAND, _CarPlayControlClientEvent);
	}else if(strcmp(kAPSCarPlayControlCommandStr_SessionCommandModesInit,inCommand)==0){
		cpcc_ulog( kLogLevelTrace, "********** CarPlayControl send dispatch **********\n" );
		dispatch_async_f(inClient->httpClientQueue, SHARK_EVENT_SESSION_POST_COMMAND_ModesInit, _CarPlayControlClientEvent);
	}


exit:
	if( err )	cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" failed    @ %N: %#m\n", inCommand, err );
	else		cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" completed @ %N\n", inCommand);


	if( requestDict ) CFReleaseNullSafe( requestDict );
	if( paramsDict ) CFReleaseNullSafe( paramsDict );
	CFReleaseNullSafe( httpMessage );
	return( err );
}

//===========================================================================================================================
//	_CarPlayControlClientPostCommandDuckAudio  duckAudio
//===========================================================================================================================

static OSStatus
	_CarPlayControlClientPostCommandDuckAudio(
		CarPlayControlClientRef inClient, CarPlayBonjourServiceRef inService, const char *inCommand )
{
	OSStatus			err;
	HTTPMessageRef		httpMessage = NULL;

	// Build the request

	err = HTTPMessageCreate( &httpMessage );
	require_noerr( err, exit );

	char url[32];
	snprintf( url, sizeof(url), "/command", "" );
	err = HTTPHeader_InitRequest( &httpMessage->header, kHTTPMethodString_POST, url, kRTSPVersionString_1pt1 );
	require_noerr( err, exit );

	//CSeq
	char CSeq[32];
	snprintf( CSeq, sizeof(CSeq), "%d", m_SyncNumber );
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_CSeq, CSeq );
	require_noerr( err, exit );

	//User-Agent
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_UserAgent, kAirPlayUserAgentStr );
	require_noerr( err, exit );

	//X-Apple-ProtocolVersion: 1
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_ProtocolVersion, "1" );
	require_noerr( err, exit );

	//Payload data

	CFDictionaryRef			requestDict =NULL;
	CFDictionaryRef			paramsDict =NULL;
	if( !requestDict )
	{
		requestDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
	}
	if( !paramsDict )
	{
		paramsDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
	}

	CFDictionarySetDouble( paramsDict, CFSTR( kAirPlayKey_DurationMs ), 500 );


	CFDictionarySetValue( requestDict, CFSTR( kAirPlayKey_Params ), paramsDict );

	if(strcmp(kAPSCarPlayControlCommandStr_SessionCommandDuckAudio,inCommand)==0){
		CFDictionarySetValue( requestDict, CFSTR( kAirPlayKey_Type ), CFSTR( kAirPlayCommand_DuckAudio ) );
		CFDictionarySetDouble( paramsDict, CFSTR( kAirPlayProperty_Volume ), -13.979399681091309 );
	}else{
		CFDictionarySetValue( requestDict, CFSTR( kAirPlayKey_Type ), CFSTR( kAirPlayCommand_UnduckAudio ) );
	}


	//[Dictionary] Controller send command
	const uint8_t*      ptr;
	size_t              len;
    if (requestDict) {
    	cpcc_ulog( kLogLevelTrace, "sendCommand duckAudio requestDict = %@ \n" ,requestDict);
        ptr = CFBinaryPlistV0Create(requestDict, &len, NULL);
        err = HTTPMessageSetBodyPtr(httpMessage, kMIMEType_AppleBinaryPlist, ptr, len);
    }

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl  Request **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	// send the request

	err = HTTPClientSendMessageSync( gHttpClient, httpMessage );
	require_noerr( err, exit );
	increaseSyncNumber();

	// Read the response header

	require_action( httpMessage->header.statusCode != 0, exit, err = kResponseErr );
	require_action( IsHTTPStatusCode_Success( httpMessage->header.statusCode ), exit, err = HTTPStatusToOSStatus( httpMessage->header.statusCode ) );

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Response **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	if(strcmp(kAPSCarPlayControlCommandStr_SessionCommandUnduckAudio,inCommand)==0){
		AirPlayModeState * modeState = AirPlayReceiverSessionControlGetAppState((mAirPlayClientConnection->session));
	}



exit:
	if( err )	cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" failed    @ %N: %#m\n", inCommand, err );
	else		cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" completed @ %N\n", inCommand);


	CFReleaseNullSafe( httpMessage );
	return( err );
}

//===========================================================================================================================
//	_CarPlayControlClientRequestUI
//===========================================================================================================================

static OSStatus
	_CarPlayControlClientRequestUI(
		CarPlayControlClientRef inClient, CarPlayBonjourServiceRef inService, const char *inCommand )
{
	OSStatus			err;
	HTTPMessageRef		httpMessage = NULL;

	// Build the request

	err = HTTPMessageCreate( &httpMessage );
	require_noerr( err, exit );

	char url[32];
	snprintf( url, sizeof(url), "/command", "" );
	err = HTTPHeader_InitRequest( &httpMessage->header, kHTTPMethodString_POST, url, kRTSPVersionString_1pt1 );
	require_noerr( err, exit );

	//CSeq
	char CSeq[32];
	snprintf( CSeq, sizeof(CSeq), "%d", m_SyncNumber );
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_CSeq, CSeq );
	require_noerr( err, exit );

	//User-Agent
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_UserAgent, kAirPlayUserAgentStr );
	require_noerr( err, exit );

	//X-Apple-ProtocolVersion: 1
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_ProtocolVersion, "1" );
	require_noerr( err, exit );

	//Payload data

	CFDictionaryRef			requestDict =NULL;
	CFDictionaryRef			paramsDict =NULL;
	if( !requestDict )
	{
		requestDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
	}
	if( !paramsDict )
	{
		paramsDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
	}

//	CFDictionarySetValue( paramsDict, CFSTR(kAirPlayKey_URL),"");

//	CFDictionarySetValue( requestDict, CFSTR( kAirPlayKey_Params ), paramsDict );
	CFDictionarySetValue( requestDict, CFSTR( kAirPlayKey_Type ), CFSTR( kAirPlayCommand_RequestUI ) );

	//[Dictionary] Controller send command
	const uint8_t*      ptr;
	size_t              len;
    if (requestDict) {
    	cpcc_ulog( kLogLevelTrace, "sendCommand-requestUI requestDict = %@ \n" ,requestDict);
        ptr = CFBinaryPlistV0Create(requestDict, &len, NULL);
        err = HTTPMessageSetBodyPtr(httpMessage, kMIMEType_AppleBinaryPlist, ptr, len);
    }

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Request **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	// send the request

	err = HTTPClientSendMessageSync( gHttpClient, httpMessage );
	require_noerr( err, exit );
	increaseSyncNumber();

	// Read the response header

	require_action( httpMessage->header.statusCode != 0, exit, err = kResponseErr );
	require_action( IsHTTPStatusCode_Success( httpMessage->header.statusCode ), exit, err = HTTPStatusToOSStatus( httpMessage->header.statusCode ) );

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Response **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	if(strcmp(kAPSCarPlayControlCommandStr_SessionCommandRequestUI,inCommand)==0){
		cpcc_ulog( kLogLevelTrace, "********** CarPlayControl don't dispatch **********\n" );
	}


exit:
	if( err )	cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" failed    @ %N: %#m\n", inCommand, err );
	else		cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" completed @ %N\n", inCommand);


	if( requestDict ) CFReleaseNullSafe( requestDict );
	if( paramsDict ) CFReleaseNullSafe( paramsDict );
	CFReleaseNullSafe( httpMessage );
	return( err );
}


//===========================================================================================================================
//	_CarPlayControlClientPostChangeViewAreaIndex
//===========================================================================================================================

static OSStatus
	_CarPlayControlClientPostChangeViewAreaIndex(
		CarPlayControlClientRef inClient, CarPlayBonjourServiceRef inService, const char *inCommand ,int index)
{
	OSStatus			err;
	HTTPMessageRef		httpMessage = NULL;

	// Build the request

	err = HTTPMessageCreate( &httpMessage );
	require_noerr( err, exit );

	char url[32];
	snprintf( url, sizeof(url), "/command", "" );
	err = HTTPHeader_InitRequest( &httpMessage->header, kHTTPMethodString_POST, url, kRTSPVersionString_1pt1 );
	require_noerr( err, exit );

	//CSeq
	char CSeq[32];
	snprintf( CSeq, sizeof(CSeq), "%d", m_SyncNumber );
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_CSeq, CSeq );
	require_noerr( err, exit );

	//User-Agent
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_UserAgent, kAirPlayUserAgentStr );
	require_noerr( err, exit );

	//X-Apple-ProtocolVersion: 1
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_ProtocolVersion, "1" );
	require_noerr( err, exit );

	//Payload data

	CFDictionaryRef			requestDict =NULL;
	CFDictionaryRef			paramsDict =NULL;
	if( !requestDict )
	{
		requestDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
	}
	if( !paramsDict )
	{
		paramsDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
	}


    char display_uuid [ 200 ];
    // __system_property_get("sys.shark.screen.uuid", display_uuid);
//    CFDictionarySetValue(requestStreamDesc, CFSTR(kAirPlayKey_UUID),CFSTR(display_uuid));
    CFDictionarySetCString( paramsDict, CFSTR( kAirPlayKey_UUID ), display_uuid ,kSizeCString);

    if( index >= 0 )
    {
    	char display_index[10] = { 0 };
    	snprintf(display_index, sizeof(display_index), "%d", index);
    	CFDictionarySetCString( paramsDict, CFSTR( kAirPlayKey_ViewAreaIndex ), display_index, kSizeCString);
    }else{
    	CFDictionarySetCString( paramsDict, CFSTR( kAirPlayKey_ViewAreaIndex ), "1" ,kSizeCString);
    }
	CFDictionarySetValue( requestDict, CFSTR( kAirPlayKey_Params ), paramsDict );
	CFDictionarySetValue( requestDict, CFSTR( kAirPlayKey_Type ), CFSTR( kAirPlayCommand_RequestViewArea ) );

	//[Dictionary] Controller send disable bluetooth
	const uint8_t*      ptr;
	size_t              len;
    if (requestDict) {
    	cpcc_ulog( kLogLevelTrace, "sendCommand requestDict = %@ \n" ,requestDict);
        ptr = CFBinaryPlistV0Create(requestDict, &len, NULL);
        err = HTTPMessageSetBodyPtr(httpMessage, kMIMEType_AppleBinaryPlist, ptr, len);
    }

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Request **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	// send the request

	err = HTTPClientSendMessageSync( gHttpClient, httpMessage );
	require_noerr( err, exit );
	increaseSyncNumber();

	// Read the response header

	require_action( httpMessage->header.statusCode != 0, exit, err = kResponseErr );
	require_action( IsHTTPStatusCode_Success( httpMessage->header.statusCode ), exit, err = HTTPStatusToOSStatus( httpMessage->header.statusCode ) );

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Response **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

//	dispatch_async_f(inClient->httpClientQueue, SHARK_EVENT_SESSION_POST_UPDATE_VIEW_AREA, _CarPlayControlClientEvent);
	uint64_t nanos=(int64_t)(1 * NSEC_PER_SEC);
	dispatch_after_f(dispatch_time( DISPATCH_TIME_NOW, nanos ), inClient->httpClientQueue,
			SHARK_EVENT_SESSION_POST_UPDATE_VIEW_AREA, _CarPlayControlClientEvent);


exit:
	if( err )	cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" failed    @ %N: %#m\n", inCommand, err );
	else		cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" completed @ %N\n", inCommand);

	if( requestDict ) CFReleaseNullSafe( requestDict );
	if( paramsDict ) CFReleaseNullSafe( paramsDict );
	CFReleaseNullSafe( httpMessage );
	return( err );
}


//===========================================================================================================================
//	_CarPlayControlClientPostDisableBluetooth
//===========================================================================================================================

static OSStatus
	_CarPlayControlClientPostDisableBluetooth(
		CarPlayControlClientRef inClient, CarPlayBonjourServiceRef inService, const char *inCommand )
{
	OSStatus			err;
	HTTPMessageRef		httpMessage = NULL;

	// Build the request

	err = HTTPMessageCreate( &httpMessage );
	require_noerr( err, exit );

	char url[32];
	snprintf( url, sizeof(url), "/command", "" );
	err = HTTPHeader_InitRequest( &httpMessage->header, kHTTPMethodString_POST, url, kRTSPVersionString_1pt1 );
	require_noerr( err, exit );

	//CSeq
	char CSeq[32];
	snprintf( CSeq, sizeof(CSeq), "%d", m_SyncNumber );
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_CSeq, CSeq );
	require_noerr( err, exit );

	//User-Agent
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_UserAgent, kAirPlayUserAgentStr );
	require_noerr( err, exit );

	//X-Apple-ProtocolVersion: 1
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_ProtocolVersion, "1" );
	require_noerr( err, exit );

	//Payload data

	CFDictionaryRef			requestDict =NULL;
	CFDictionaryRef			paramsDict =NULL;
	if( !requestDict )
	{
		requestDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
	}
	if( !paramsDict )
	{
		paramsDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
	}

	char	deviceId[ 40 ];
	memset(deviceId,0,40);
	// __system_property_get("sys.xq.product.deviceid", deviceId);

	CFDictionarySetCString( paramsDict, CFSTR( kAirPlayKey_DeviceID ), deviceId ,kSizeCString);

	CFDictionarySetValue( requestDict, CFSTR( kAirPlayKey_Params ), paramsDict );
	CFDictionarySetValue( requestDict, CFSTR( kAirPlayKey_Type ), CFSTR( kAirPlayCommand_DisableBluetooth ) );

	//[Dictionary] Controller send disable bluetooth
	const uint8_t*      ptr;
	size_t              len;
    if (requestDict) {
    	cpcc_ulog( kLogLevelTrace, "sendCommand requestDict = %@ \n" ,requestDict);
        ptr = CFBinaryPlistV0Create(requestDict, &len, NULL);
        err = HTTPMessageSetBodyPtr(httpMessage, kMIMEType_AppleBinaryPlist, ptr, len);
    }

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Request **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	// send the request

	err = HTTPClientSendMessageSync( gHttpClient, httpMessage );
	require_noerr( err, exit );
	increaseSyncNumber();

	// Read the response header

	require_action( httpMessage->header.statusCode != 0, exit, err = kResponseErr );
	require_action( IsHTTPStatusCode_Success( httpMessage->header.statusCode ), exit, err = HTTPStatusToOSStatus( httpMessage->header.statusCode ) );

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Response **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	dispatch_async_f(inClient->httpClientQueue, SHARK_EVENT_SESSION_POST_CMD_DISABLE_BLUETOOTH, _CarPlayControlClientEvent);

exit:
	if( err )	cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" failed    @ %N: %#m\n", inCommand, err );
	else		cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" completed @ %N\n", inCommand);

	if( requestDict ) CFReleaseNullSafe( requestDict );
	if( paramsDict ) CFReleaseNullSafe( paramsDict );
	CFReleaseNullSafe( httpMessage );
	return( err );
}

//===========================================================================================================================
//	_CarPlayControlClientPostChangeUIContext
//===========================================================================================================================

static OSStatus
	_CarPlayControlClientPostChangeUIContext(
		CarPlayControlClientRef inClient, CarPlayBonjourServiceRef inService, const char *inCommand )
{
	OSStatus			err;
	HTTPMessageRef		httpMessage = NULL;

	// Build the request

	err = HTTPMessageCreate( &httpMessage );
	require_noerr( err, exit );

	char url[32];
	snprintf( url, sizeof(url), "/command", "" );
	err = HTTPHeader_InitRequest( &httpMessage->header, kHTTPMethodString_POST, url, kRTSPVersionString_1pt1 );
	require_noerr( err, exit );

	//CSeq
	char CSeq[32];
	snprintf( CSeq, sizeof(CSeq), "%d", m_SyncNumber );
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_CSeq, CSeq );
	require_noerr( err, exit );

	//User-Agent
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_UserAgent, kAirPlayUserAgentStr );
	require_noerr( err, exit );

	//X-Apple-ProtocolVersion: 1
	err = HTTPHeader_AddField( &httpMessage->header, kHTTPHeader_ProtocolVersion, "1" );
	require_noerr( err, exit );

	//Payload data

	CFDictionaryRef			requestDict =NULL;
	CFDictionaryRef			paramsDict =NULL;
	if( !requestDict )
	{
		requestDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
	}
	if( !paramsDict )
	{
		paramsDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
	}


	CFDictionarySetCString( paramsDict, CFSTR( kAirPlayKey_ClientPID ), "653" ,kSizeCString);
	CFDictionarySetCString( paramsDict, CFSTR( kAirPlayKey_URL ), "mobilephone" ,kSizeCString);

	CFDictionarySetValue( requestDict, CFSTR( kAirPlayKey_Params ), paramsDict );
	CFDictionarySetValue( requestDict, CFSTR( kAirPlayKey_Type ), CFSTR( kAirPlayCommand_ChangeUIContext ) );

	//[Dictionary] Controller send disable bluetooth
	const uint8_t*      ptr;
	size_t              len;
    if (requestDict) {
    	cpcc_ulog( kLogLevelTrace, "sendCommand requestDict = %@ \n" ,requestDict);
        ptr = CFBinaryPlistV0Create(requestDict, &len, NULL);
        err = HTTPMessageSetBodyPtr(httpMessage, kMIMEType_AppleBinaryPlist, ptr, len);
    }

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Request **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	// send the request

	err = HTTPClientSendMessageSync( gHttpClient, httpMessage );
	require_noerr( err, exit );
	increaseSyncNumber();

	// Read the response header

	require_action( httpMessage->header.statusCode != 0, exit, err = kResponseErr );
	require_action( IsHTTPStatusCode_Success( httpMessage->header.statusCode ), exit, err = HTTPStatusToOSStatus( httpMessage->header.statusCode ) );

	cpcc_ulog( kLogLevelTrace, "********** CarPlayControl Response **********\n" );
	cpcc_ulog( kLogLevelTrace, "%@\n", httpMessage );

	dispatch_async_f(inClient->httpClientQueue, SHARK_EVENT_SESSION_POST_CMD_CHANGE_UI_CONTEXT, _CarPlayControlClientEvent);

exit:
	if( err )	cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" failed    @ %N: %#m\n", inCommand, err );
	else		cpcc_ulog( kLogLevelVerbose, "CarPlayControl command \"%s\" completed @ %N\n", inCommand);

	if( requestDict ) CFReleaseNullSafe( requestDict );
	if( paramsDict ) CFReleaseNullSafe( paramsDict );
	CFReleaseNullSafe( httpMessage );
	return( err );
}

static void _CarPlayControlClientConnect( void *inCtx )
{
	_ConnectContext *			    ctx = (_ConnectContext*) inCtx;
	CarPlayControlClientRef			client = ctx->controller->client;
	CarPlayBonjourServiceRef		carPlayService = NULL;
	Boolean							carPlayServiceIsActive = false;
	CFIndex							serviceCount;

	if(gClientStarted == 1){
		return;
	}
	gClientStarted = 1;

	char	oemBrand [ 200 ] =  "ApplePie";
	// __system_property_get("persist.sys.oem.brand", oemBrand);
	memset(gOEMBrand, 0, 200);
	memcpy(gOEMBrand, oemBrand, 200);

	require_action( client->started, exit, ctx->err = kStateErr );

	ctx->err = CarPlayControllerCopyBestService( ctx->controller, &carPlayService, &carPlayServiceIsActive );
	require_noerr( ctx->err, exit );
	mAirPlayClientConnection = (struct AirPlayClientConnection * )malloc(sizeof(struct AirPlayClientConnection));
	MFiSAP_Create( &mAirPlayClientConnection->MFiSAP, kMFiSAPVersion1 );
	//这里需要保存全局引用
	gCarPlayClient  = client;
	gCarPlayService = carPlayService;
	//这里需要判读，是否需要pair-setup ---> pair-verify 流程
	int match = PairingSessionMatchPeerPublicHKID(gRemotePublicHKID);
	cpcc_ulog( kLogLevelTrace, "shark-match %d \n", match );


	//special handle link >>>
	//马自达放久会卡死的问题 gUsbVid:0x2996 gUsbPid:0x0000
	//福特主机卡死 gUsbVid:0x042f gUsbPid:0x0601
	//路虎主机断开问题  gUsbVid:0x8086 gUsbPid:0x9999
	// 0x2b96 pid:0x0104
	// 0x04da pid:0x3210 skoda主机一定要走auth
	// 大众主机 vid:0x2996 pid:0x0000 德赛 5GG035280D
	// 5GG035280D 5GG035280E
	char	model [ 50 ] =  "";
	// __system_property_get("sys.shark.oem.car.model", model);
	gHomeKitEnable = gBonjourPairingHK;
	if (gUsbVid == 0x2996 && gUsbPid == 0x0000)
	{
		if( strcasecmp("5GG035280D",model ) == 0 || strstr(model,"5GG035280") != NULL
				|| strstr(model,"19D035280") != NULL )
		{
			//特殊处理的车机主机
			gHomeKitEnable = 0;
		}
	}
	//斯巴鲁20240319:0x06d3 pid:0x60a0
	//台湾路虎 vid:0x1004 pid:0x7722
	if ((gUsbVid == 0x2b96 && gUsbPid == 0x0104)
			||(gUsbVid == 0x06d3 && gUsbPid == 0x60a0)
			||(gUsbVid == 0x1004 && gUsbPid == 0x7722)
			)
	{
		//特殊处理的车机主机
		gHomeKitEnable = 0;
	}
	//special handle link <<<
//	gHomeKitEnable = 0; //测试http使用
	//将IPV6址读取到
	 char ipv6_address[INET6_ADDRSTRLEN] = { 0 };
	// __system_property_get("sys.shark.net.accessory.address", ipv6_address);
	if(strlen(ipv6_address) > 0 )
	{
		// __system_property_set("sys.shark.net.accessory.address", "");
		memset( gBonjourIPAddress, 0, 100);
		strncpy(gBonjourIPAddress,(char *)ipv6_address,strlen((char *)ipv6_address));
		cpcc_ulog( kLogLevelTrace, "gBonjourIPAddress %s \n", gBonjourIPAddress );
	}
	if(match == kNoErr && gHomeKitEnable == 1)
	{
		ctx->err = _CarPlayControlClientPairVerify( client, carPlayService, kAPSCarPlayControlCommandStr_PairVerify1 );
	}else{
		cpcc_ulog( kLogLevelTrace, "gHomeKitEnable %d \n", gHomeKitEnable );
		if(gHomeKitEnable == 0){
			//注意:直接走auth-setup，奔驰主机播放视频会断开
			ctx->err = _CarPlayControlClientAuthSetup( client, carPlayService, kAPSCarPlayControlCommandStr_AuthSetup );
		}else{
			ctx->err = _CarPlayControlClientPairSetup( client, carPlayService, kAPSCarPlayControlCommandStr_PairSetup1 );
		}
	}
	cpcc_ulog( kLogLevelTrace, "shark-ctx->err %d \n", ctx->err );
	require_noerr( ctx->err, exit );

exit:
	if( ctx->err != kNoErr )
	{
		if( carPlayServiceIsActive )
		{
			// Kick of a new resolve, in case the address or port number changed

			CarPlayBonjourServiceResolveAddress( carPlayService );

			// Also try reconfirming the device

			CFDictionaryRef device = _CarPlayControllerCopyCurrentDevice( ctx->controller );
			BonjourBrowser_ReconfirmDevice( client->browser, device );
			CFRelease( device );

		}
		else
		{
			// Probably gone for good, so remove the inactive services

			_CarPlayControllerForgetInactiveServices( ctx->controller, &serviceCount );

			if( serviceCount == 0 )
				_CarPlayControlClientRemoveController( client, ctx->controller );

		}
	}
	//CFReleaseNullSafe( carPlayService );
}

OSStatus CarPlayControlClientConnect( CarPlayControlClientRef inClient, CarPlayControllerRef inController,uint16_t vid, uint16_t pid )
{
	gUsbVid = vid;
	gUsbPid = pid;
	_ConnectContext		commandCtx;

	memset( &commandCtx, 0, sizeof( commandCtx ) );
	require_action( inClient && inController && inController->client == inClient, exit, commandCtx.err = kParamErr );

	commandCtx.controller = inController;

	dispatch_sync_f( inClient->internalRequestQueue, &commandCtx, _CarPlayControlClientConnect );

exit:
	return( commandCtx.err );
}

OSStatus CarPlayControlClientConnectWithCarPlaySession( CarPlayControlClientRef inClient,void *inIPAddress, int inPort,void * inSourceVersion,
		void * inDeviceID,void * inPublicKey,
		uint16_t inVid, uint16_t inPid )
{
	gUsbVid = inVid;
	gUsbPid = inPid;




	memset( gBonjourIPAddress, 0, 100);
	memset( gBonjourDeviceID, 0, 100);
	memset( gBonjourPublicKey, 0, 100);

	strncpy(gBonjourIPAddress,(char *)inIPAddress,strlen((char *)inIPAddress));
	gBonjourPort =  inPort;
	strncpy(gBonjourDeviceID,(char *)inDeviceID,strlen((char *)inDeviceID));
	strncpy(gBonjourPublicKey,(char *)inPublicKey,strlen((char *)inPublicKey));

	//这里判读
	if(strlen(gBonjourIPAddress) == 0 )
	{
		cpcc_ulog( kLogLevelTrace, "gBonjourIPAddress is empty.\n");
		char	remoteIP [ 50 ] =  { 0 };
		// __system_property_get("persist.shark.remote.cp.ip", remoteIP);
		strncpy(gBonjourIPAddress,(char *)remoteIP,strlen((char *)remoteIP));
	}

	cpcc_ulog( kLogLevelTrace, "gBonjourIPAddress %s%s \n", gBonjourIPAddress ,"%usb0");
	cpcc_ulog( kLogLevelTrace, "gBonjourDeviceID %s \n", gBonjourDeviceID );
	cpcc_ulog( kLogLevelTrace, "gBonjourPublicKey %s \n", gBonjourPublicKey );

	// See if we have an existing entry to update
	CarPlayController *		controller = NULL;
	gBonjourPairingHK = 1;
	int err = 0;

	// Otherwise create new

//	if( !controller )
//	{
//		_CarPlayControllerCreate( &controller, inClient );
//		if( controller )
//			CFArrayAppendValue( inClient->controllers, controller );
//	}

	// Update the controller and notify our client

//	if( controller )
//	{
//		_CarPlayControllerUpdate( controller, inEventInfo, NULL );
//		_CarPlayControlClientPostEvent( inClient, kCarPlayControlClientEvent_AddOrUpdateController, controller );
//		CFRelease( controller );
//	}

	if(gClientStarted == 1){
		return -1;
	}
	gClientStarted = 1;

	char	oemBrand [ 200 ] =  "ApplePie";
	// __system_property_get("persist.sys.oem.brand", oemBrand);
	memset(gOEMBrand, 0, 200);
	memcpy(gOEMBrand, oemBrand, 200);


	mAirPlayClientConnection = (struct AirPlayClientConnection * )malloc(sizeof(struct AirPlayClientConnection));
	MFiSAP_Create( &mAirPlayClientConnection->MFiSAP, kMFiSAPVersion1 );
	//这里需要保存全局引用
	gCarPlayClient  = inClient;
	gCarPlayService = NULL;
	gHomeKitEnable = gBonjourPairingHK;
	// vid:0x1004 pid:0x7722
	if ((gUsbVid == 0x2b96 && gUsbPid == 0x0104)
			||(gUsbVid == 0x04da && gUsbPid == 0x3210)
			||(gUsbVid == 0x1004 && gUsbPid == 0x7722)
			)
	{
		//特殊处理的车机主机
		gHomeKitEnable = 0;
	}
//	gHomeKitEnable = 0; //测试http使用
	//special handle link <<<
	cpcc_ulog( kLogLevelTrace, "gHomeKitEnable %d \n", gHomeKitEnable );
	if(gHomeKitEnable == 0){
		//注意:直接走auth-setup，奔驰主机播放视频会断开
		err = _CarPlayControlClientAuthSetup( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_AuthSetup );
	}else{
		err = _CarPlayControlClientPairSetup( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_PairSetup1 );
	}
	return err;
}

OSStatus	CarPlayControlClientCheckAudioStream( int inType, uint64_t * outConnectionID)
{
	return AirPlayCheckAudioStreamContext(mAirPlayClientConnection->session, inType, outConnectionID);
}

OSStatus	CarPlayControlClientModesChanged( )
{
	dispatch_async_f( gCarPlayClient->httpClientQueue, SHARK_EVENT_SESSION_MODES_CHANGED, _CarPlayControlEnqueueTask );
	return 0;
}
OSStatus	CarPlayControlClientGotoBackground( )
{
	_CarPlayControlClientPostCommandModesChanged( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionCommandModesChanged );
	_CarPlayControlClientDearDownScreen( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionTeardownScreen );
	return 0;
}

OSStatus	CarPlayControlClientChangeModesCommandResponse( )
{
	_CarPlayControlClientPostCommandModesChanged( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionCommandModesChanged );
	return 0;
}

OSStatus	CarPlayControlClientAudioStart( )
{
	dispatch_async_f( gCarPlayClient->httpClientQueue, SHARK_EVENT_SESSION_AUDIO_SETUP_CHANNEL, _CarPlayControlClientEvent);
	return 0;
}

OSStatus	CarPlayControlClientAudioStop( )
{
	dispatch_async_f( gCarPlayClient->httpClientQueue, SHARK_EVENT_SESSION_TEARDOWN_AUDIO, _CarPlayControlClientEvent);
	return 0;
}



OSStatus	CarPlayControlClientModesChangedAudio( )
{
	dispatch_async_f( gCarPlayClient->httpClientQueue, SHARK_EVENT_SESSION_MODES_CHANGED_AUDIO, _CarPlayControlEnqueueTask );
	return 0;
}

OSStatus	CarPlayControlClientDuckAudio( )
{
	dispatch_async_f( gCarPlayClient->httpClientQueue, SHARK_EVENT_SESSION_MODES_DUCK_AUDIO, _CarPlayControlEnqueueTask );
	dispatch_async_f( gCarPlayClient->httpClientQueue, AUDIO_CHANNEL_NAVIGATION, _CarPlayControlClientAudioFocusGain);
	return 0;
}

OSStatus	CarPlayControlClientUnduckAudio( )
{
	dispatch_async_f( gCarPlayClient->httpClientQueue, SHARK_EVENT_SESSION_MODES_UNDUCK_AUDIO, _CarPlayControlEnqueueTask );
	return 0;
}

OSStatus	CarPlayControlClientBack2Home( )
{
	dispatch_async_f(gCarPlayClient->httpClientQueue, SHARK_EVENT_SESSION_BACK_HOME, _CarPlayControlClientEvent);
	return 0;
}

OSStatus	CarPlayControlClientChangeViewAreaIndex( )
{
	dispatch_async_f(gCarPlayClient->httpClientQueue, SHARK_EVENT_SESSION_POST_VIEW_AREA_INDEX, _CarPlayControlClientEvent);
	return 0;
}

OSStatus	CarPlayControlClientTearDownScreen( )
{
	dispatch_async_f(gCarPlayClient->httpClientQueue, SHARK_EVENT_SESSION_TEARDOWN_SCREEN, _CarPlayControlClientEvent);
	return 0;
}

OSStatus	CarPlayControlClientTearDownAudio( )
{
	dispatch_async_f(gCarPlayClient->httpClientQueue, SHARK_EVENT_SESSION_TEARDOWN_AUDIO, _CarPlayControlClientEvent);
	return 0;
}


OSStatus	CarPlayControlClientResumeScreen( )
{
	cpcc_ulog( kLogLevelWarning, "###_TimingMachine CarPlayControlClientResumeScreen.\n");
	//同时需要启动时间timing
	dispatch_async_f(gCarPlayClient->httpClientQueue, SHARK_EVENT_SESSION_RESUME_SCREEN, _CarPlayControlClientEvent);
	return 0;
}

static void _CarPlayControlEnqueueTask( int eventId )
{
//	cpcc_ulog( kLogLevelTrace, "_CarPlayControlEnqueueTask  eventId= %d \n",eventId);
	if( SHARK_EVENT_PAIR_SETUP ==eventId )
	{
		_CarPlayControlClientPairSetup( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_PairSetup1 );
	}
	else if( SHARK_EVENT_PAIR_SETUP1 ==eventId )
	{
		 _CarPlayControlClientPairSetup2( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_PairSetup2 );
	}else if(SHARK_EVENT_PAIR_SETUP2 ==eventId ){
		_CarPlayControlClientPairSetup3( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_PairSetup3 );
	}else if(SHARK_EVENT_PAIR_SETUP3 ==eventId ){
		_CarPlayControlClientPairVerify( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_PairVerify1 );
	}else if(SHARK_EVENT_PAIR_VERIFY1 ==eventId ){
		_CarPlayControlClientPairVerify2( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_PairVerify2 );
	}else if(SHARK_EVENT_PAIR_VERIFY2 ==eventId ){
		_CarPlayControlClientAuthSetup( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_AuthSetup );
	}else if(SHARK_EVENT_PAIR_AUTH_SETUP ==eventId ){
		_CarPlayControlClientRtspOptions( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_RtspOptions );
	}else if(SHARK_EVENT_RTSP_OPTIONS ==eventId ){
		_CarPlayControlClientRtspSetup( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionSetup );
	}else if(SHARK_EVENT_SESSION_SETUP ==eventId ){
		_CarPlayControlClientGetInfo( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_GetInfo );
	}else if(SHARK_EVENT_SESSION_GET_INFO ==eventId ){
		//info > record　> modesChanged > disableBluetooth > modesChanged > setup-screen
		//step 0
		_CarPlayControlClientRtspRecord( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_Record );
	}else if(SHARK_EVENT_SESSION_RECORD ==eventId ){
		//record成功后，需要发post/command
		//step 1
		AirPlayModeState * modeState = AirPlayReceiverSessionControlGetAppState((mAirPlayClientConnection->session));
		if( modeState != NULL ){
			//这里很重要会导致奥迪A6连接上黑屏
			if(modeState->screen == kAirPlayEntity_NotApplicable)
			{
				modeState->screen = kAirPlayEntity_Accessory;
				modeState->permScreen = kAirPlayEntity_Accessory;
			}

			if(modeState->mainAudio == kAirPlayEntity_NotApplicable)
			{
				modeState->mainAudio = kAirPlayEntity_Accessory;
				modeState->permMainAudio = kAirPlayEntity_Accessory;
			}
			modeState->speech.mode = kAirPlaySpeechMode_None;
			_CarPlayControlClientPostCommandModesChanged( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionCommandModesInit );
		}
	}else if(SHARK_EVENT_SESSION_POST_COMMAND_ModesInit == eventId){
		//step 2
		_CarPlayControlClientPostDisableBluetooth( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionDisableBlutooth );
	}else if(SHARK_EVENT_SESSION_POST_CMD_DISABLE_BLUETOOTH == eventId){
		//step 3
		AirPlayModeState * modeState = AirPlayReceiverSessionControlGetAppState((mAirPlayClientConnection->session));
		cpcc_ulog( kLogLevelTrace, "SHARK_EVENT_SESSION_POST_CMD_DISABLE_BLUETOOTH modeState->screen = %d \n",modeState->screen);
		cpcc_ulog( kLogLevelTrace, "SHARK_EVENT_SESSION_POST_CMD_DISABLE_BLUETOOTH modeState->initalScreenAccessory = %d \n",modeState->initalScreenAccessory);
		if(modeState->screen == kAirPlayEntity_Accessory)
		{
			if(modeState->initalScreenAccessory == 0)
			{
				modeState->screen = kAirPlayEntity_Controller;
			}
			modeState->permScreen = kAirPlayEntity_Controller;
			_CarPlayControlClientPostCommandModesChanged( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionCommand );
		}
		//先发送changeUIContext
//		_CarPlayControlClientPostChangeUIContext( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionCommandChangeUIContext );
	}else if(SHARK_EVENT_SESSION_POST_COMMAND == eventId){
		//step 4
		AirPlayModeState * modeState = AirPlayReceiverSessionControlGetAppState((mAirPlayClientConnection->session));
		cpcc_ulog( kLogLevelTrace, "_CarPlayControlEnqueueTask screen = %d \n",modeState->screen);
		cpcc_ulog( kLogLevelTrace, "_CarPlayControlEnqueueTask gScreenStarted = %d \n",gScreenStarted);
		if(modeState->screen == kAirPlayEntity_Controller)
		{

			if(modeState->transferViewArea ){
				//Ford Kuga
				_CarPlayControlClientFeedback( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionFeedback );
				//先切成大屏
				int targetAreaIndex = modeState->changeViewAreaIndex;
				_CarPlayControlClientPostChangeViewAreaIndex( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_ViewAreaIndex, targetAreaIndex);
			}else{
				_CarPlayControlClientRtspSetupScreen( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionSetupScreen );
			}

		}else{
			cpcc_ulog( kLogLevelTrace, "_CarPlayControlEnqueueTask kAPSCarPlayControlCommandStr_SessionFeedback continue \n");
			_CarPlayControlClientFeedback( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionFeedback );
		}

	}
	else if(SHARK_EVENT_SESSION_POST_UPDATE_VIEW_AREA == eventId){
		_CarPlayControlClientRtspSetupScreen( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionSetupScreen );
	}else if(SHARK_EVENT_SESSION_POST_CMD_CHANGE_UI_CONTEXT == eventId){
		AirPlayModeState * modeState = AirPlayReceiverSessionControlGetAppState((mAirPlayClientConnection->session));
		if(modeState->screen == kAirPlayEntity_Accessory)
		{
			modeState->screen = kAirPlayEntity_Controller;
			modeState->permScreen = kAirPlayEntity_Controller;
			_CarPlayControlClientPostCommandModesChanged( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionCommand );
		}
	}else if(SHARK_EVENT_SESSION_SCREEN_START ==eventId ){
		_CarPlayControlClientFeedback( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionFeedback );
	}else if(SHARK_EVENT_SESSION_FEEDBACK ==eventId ){
		_CarPlayControlClientFeedback( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionFeedback );
	}else if(SHARK_EVENT_SESSION_AUDIO_START ==eventId ){
		_CarPlayControlClientPostCommandModesChanged( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionCommandInteractive );
	}else if(SHARK_EVENT_SESSION_MODES_CHANGED == eventId ){
			_CarPlayControlClientPostCommandModesChanged( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionCommandModesChanged );
	}else if(SHARK_EVENT_SESSION_MODES_CHANGED_TEARDOWN == eventId ){
		//TearDown Audio
		_CarPlayControlClientPostCommandModesChanged( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionCommandModesChangedTearDown );
	}else if(SHARK_EVENT_SESSION_MODES_CHANGED_AUDIO==eventId ){
		_CarPlayControlClientPostCommandModesChanged( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionCommandModesChangedAudio );
	}else if(SHARK_EVENT_SESSION_BACK_HOME == eventId ){
		cpcc_ulog( kLogLevelTrace, "_CarPlayControlEnqueueTask SHARK_EVENT_SESSION_BACK2_HOME \n");
		_CarPlayControlClientRequestUI( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionCommandRequestUI );
	}else if(SHARK_EVENT_SESSION_TEARDOWN_SCREEN ==eventId ){
		cpcc_ulog( kLogLevelTrace, "_CarPlayControlEnqueueTask SHARK_EVENT_SESSION_TEARDOWN_SCREEN \n");
		_CarPlayControlClientDearDownScreen( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionTeardownScreen );
	}else if(SHARK_EVENT_SESSION_RESUME_SCREEN ==eventId ){
		cpcc_ulog( kLogLevelTrace, "_CarPlayControlEnqueueTask SHARK_EVENT_SESSION_RESUME_SCREEN \n");
		if(gScreenStarted == 0)
		{
			_CarPlayControlClientRtspSetupScreen( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionResumeScreen );
		}
	}else if(SHARK_EVENT_SESSION_AUDIO_SETUP_CHANNEL ==eventId ){
		cpcc_ulog( kLogLevelTrace, "_CarPlayControlEnqueueTask SHARK_EVENT_SESSION_AUDIO_SETUP_CHANNEL \n");
		_CarPlayControlClientRtspSetupAudio( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionSetupAudio );
	}else if(SHARK_EVENT_SESSION_TEARDOWN_AUDIO ==eventId ){
		cpcc_ulog( kLogLevelTrace, "AudioTrace _CarPlayControlEnqueueTask SHARK_EVENT_SESSION_TEARDOWN_AUDIO \n");
		_CarPlayControlClientDearDownAudio( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionTeardownAudio );
	}else if(SHARK_EVENT_SESSION_MODES_DUCK_AUDIO == eventId ){
		cpcc_ulog( kLogLevelTrace, "_CarPlayControlEnqueueTask SHARK_EVENT_SESSION_MODES_DUCK_AUDIO \n");
		_CarPlayControlClientPostCommandDuckAudio( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionCommandDuckAudio );
	}else if(SHARK_EVENT_SESSION_MODES_UNDUCK_AUDIO == eventId ){
		cpcc_ulog( kLogLevelTrace, "_CarPlayControlEnqueueTask SHARK_EVENT_SESSION_MODES_UNDUCK_AUDIO \n");
		_CarPlayControlClientPostCommandDuckAudio( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_SessionCommandUnduckAudio );
	}else if(SHARK_EVENT_SESSION_HOMEKIT_DISABLE == eventId ){
		cpcc_ulog( kLogLevelTrace, "_CarPlayControlEnqueueTask SHARK_EVENT_SESSION_HOMEKIT_DISABLE \n");
		_CarPlayControlClientAuthSetup( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_AuthSetup );
	}else if(SHARK_EVENT_SESSION_POST_VIEW_AREA_INDEX == eventId ){
		cpcc_ulog( kLogLevelTrace, "_CarPlayControlEnqueueTask SHARK_EVENT_SESSION_POST_VIEW_AREA_INDEX \n");
		_CarPlayControlClientPostChangeViewAreaIndex( gCarPlayClient, gCarPlayService, kAPSCarPlayControlCommandStr_ViewAreaIndex,-1);
	}

}

static void _CarPlayControlClientEvent( int eventId )
{
//	cpcc_ulog( kLogLevelTrace, "_CarPlayControlClientEvent  eventId= %d \n",eventId);
	dispatch_sync_f( gCarPlayClient->internalRequestQueue, eventId, _CarPlayControlEnqueueTask );

}

static void _CarPlayControlClientAudioFocusGain( int targetChannel, int eventId )
{

	AirPlayReceiverSessionControlAudioFocusChanged(mAirPlayClientConnection->session, targetChannel, 1);
}

static void _CarPlayControlClientAudioFocusLost( int targetChannel, int eventId )
{
	AirPlayReceiverSessionControlAudioFocusChanged(mAirPlayClientConnection->session, targetChannel, 0);

}


//===========================================================================================================================
//	CarPlayControlClientDisconnect
//===========================================================================================================================

typedef struct
{
	CarPlayControllerRef	controller;
	OSStatus				err;
} _DisconnectContext;

static void _CarPlayControlClientDisconnect( void *inCtx )
{
	_DisconnectContext *		ctx = (_DisconnectContext*) inCtx;
	CarPlayControlClientRef		client = ctx->controller->client;

	require_action( client->started, exit, ctx->err = kStateErr );
	require_action( client->server, exit, ctx->err = kInternalErr );

	cpcc_ulog( kLogLevelTrace, "_CarPlayControlClientDisconnect Oops \n");
	ctx->err = AirPlayReceiverServerControlAsync( client->server, CFSTR( kAirPlayCommand_SessionDied ),
					NULL, NULL, NULL, NULL, NULL );
	require_noerr( ctx->err, exit );

exit:
	;
}

OSStatus CarPlayControlClientDisconnect( CarPlayControlClientRef inClient, CarPlayControllerRef inController )
{
	_DisconnectContext		commandCtx;

	memset( &commandCtx, 0, sizeof( commandCtx ) );
	require_action( inClient && inController && inController->client == inClient, exit, commandCtx.err = kParamErr );

	commandCtx.controller = inController;

	dispatch_sync_f( inClient->internalQueue, &commandCtx, _CarPlayControlClientDisconnect );

exit:
	return( commandCtx.err );
}

typedef struct
{
	CarPlayControllerRef	controller;
	OSStatus				err;
	const char *					strData;
} _STADisconnectContext;

static void _CarPlayControlClientSTADisconnect( void *inCtx )
{
	_STADisconnectContext *			ctx = (_STADisconnectContext*) inCtx;

	CarPlayBonjourServiceRef		carPlayService = NULL;
	Boolean							carPlayServiceIsActive = false;

	const char *					hostName = NULL;
	uint16_t						port = 0;
	uint32_t						interfaceNdx = 0;
	Boolean							match;

	require_action( ctx->controller->client->started, exit, ctx->err = kStateErr );
	require_action( ctx->controller->client->server, exit, ctx->err = kInternalErr );
	require_action( ctx->strData, exit, ctx->err = kParamErr );

	ctx->err = CarPlayControllerCopyBestService( ctx->controller, &carPlayService, &carPlayServiceIsActive );
	require_noerr( ctx->err, exit );
	require_action(carPlayServiceIsActive, exit, ctx->err = kStateErr );

	ctx->err = CarPlayBonjourServiceGetAddress( carPlayService, &hostName, &port, &interfaceNdx );
	require_noerr( ctx->err, exit );

	ctx->err = CompareHostnameIPAddress( hostName, &port, ctx->strData, &match );
	require_noerr( ctx->err, exit );

	if( match ) {
		_CarPlayControlClientDisconnect( ctx );
	}

exit:
	CFReleaseNullSafe( carPlayService );
}

OSStatus CarPlayControlClientSTALeft( CarPlayControlClientRef inClient, CarPlayControllerRef inController, const char *inIPAddress )
{
	_STADisconnectContext		commandCtx;

	memset( &commandCtx, 0, sizeof( commandCtx ) );
	require_action( inIPAddress && inClient && inController && inController->client == inClient, exit, commandCtx.err = kParamErr );

	commandCtx.controller = inController;
	commandCtx.strData = inIPAddress;

	dispatch_sync_f( inClient->internalQueue, &commandCtx, _CarPlayControlClientSTADisconnect );

exit:
	return ( commandCtx.err );
}


//===========================================================================================================================
//	CarPlayControlClientSetDelegate
//===========================================================================================================================
void CarPlayControlClientSetDelegate( const CarPlayControlClientDelegate *inDelegate )
{
	gCarPlayControlClientDelegate = *inDelegate;
}

